From eac9863c1db98521cb5579196a75824dd54dd34b Mon Sep 17 00:00:00 2001 From: Christopher Durand Date: Wed, 9 Feb 2022 00:49:25 +0100 Subject: [PATCH 01/35] [ext] Update sam and modm-devices submodules --- ext/microchip/sam | 2 +- ext/modm-devices | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ext/microchip/sam b/ext/microchip/sam index 718fa0f98c..f903c3f55c 160000 --- a/ext/microchip/sam +++ b/ext/microchip/sam @@ -1 +1 @@ -Subproject commit 718fa0f98cbc7d35becddabc3612d73d03929cf3 +Subproject commit f903c3f55c1273ce1d121ee860e4fe7d2c6033bb diff --git a/ext/modm-devices b/ext/modm-devices index 05fca29f63..2714f2321f 160000 --- a/ext/modm-devices +++ b/ext/modm-devices @@ -1 +1 @@ -Subproject commit 05fca29f6398f847a99215ed0ab07d54f541cc3a +Subproject commit 2714f2321f89bece09f0b339909ebe37e133858d From 3e5a611a270116f231fcdf0965ba27c3ffba3f09 Mon Sep 17 00:00:00 2001 From: Christopher Durand Date: Tue, 19 Oct 2021 12:06:00 +0200 Subject: [PATCH 02/35] [repo] Enable SAMD5x/SAME5x device family --- repo.lb | 1 + src/modm/platform/extint/sam/module.lb | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/repo.lb b/repo.lb index 570f35afce..3e9d94ee66 100644 --- a/repo.lb +++ b/repo.lb @@ -87,6 +87,7 @@ class DevicesCache(dict): "stm32l0", "stm32l1", "stm32l4", "stm32l5", "at90", "attiny", "atmega", "samd21", "samg55", "samv70", + "samd51", "same51", "same53", "same54", "rp2040", "hosted"] device_file_names = [dfn for dfn in device_file_names if any(s in dfn for s in supported)] diff --git a/src/modm/platform/extint/sam/module.lb b/src/modm/platform/extint/sam/module.lb index ab3272c3de..8433841392 100644 --- a/src/modm/platform/extint/sam/module.lb +++ b/src/modm/platform/extint/sam/module.lb @@ -15,7 +15,7 @@ def init(module): module.description = "External Interrupt" def prepare(module, options): - if not options[":target"].partname.startswith("samd"): + if not options[":target"].partname.startswith("samd2"): return False module.depends(":cmsis:device", ":platform:gclk", ":platform:gpio") From b4a28a8aecd245da465b12ea2e31d097d9389ee5 Mon Sep 17 00:00:00 2001 From: Christopher Durand Date: Tue, 19 Oct 2021 18:24:30 +0200 Subject: [PATCH 03/35] [sam] Add minimum GCLK support for D5x/E5x devices --- src/modm/platform/clock/sam/gclk.cpp.in | 4 ++- .../clock/sam/{gclk.hpp => gclk.hpp.in} | 11 ++++--- src/modm/platform/clock/sam/gclk_impl.hpp.in | 29 +++++++++++++++++-- src/modm/platform/clock/sam/module.lb | 24 +++++++++++++-- 4 files changed, 59 insertions(+), 9 deletions(-) rename src/modm/platform/clock/sam/{gclk.hpp => gclk.hpp.in} (93%) diff --git a/src/modm/platform/clock/sam/gclk.cpp.in b/src/modm/platform/clock/sam/gclk.cpp.in index b2e3890a41..a5daf911ee 100644 --- a/src/modm/platform/clock/sam/gclk.cpp.in +++ b/src/modm/platform/clock/sam/gclk.cpp.in @@ -1,6 +1,7 @@ /* * Copyright (c) 2020-2021, Niklas Hauser * Copyright (c) 2020, Erik Henriksson + * Copyright (c) 2022, Christopher Durand * * This file is part of the modm project. * @@ -23,6 +24,7 @@ namespace modm::platform constinit uint16_t modm_fastdata delay_fcpu_MHz(computeDelayMhz(GenericClockController::BootFrequency)); constinit uint16_t modm_fastdata delay_ns_per_loop(computeDelayNsPerLoop(GenericClockController::BootFrequency)); +%% if device_family == "d2x" bool GenericClockController::initOsc8MHz(uint32_t waitCycles) { @@ -118,5 +120,5 @@ GenericClockController::setSystemClock(ClockSource source, uint32_t waitCycles) return waitCycles; } - +%% endif } diff --git a/src/modm/platform/clock/sam/gclk.hpp b/src/modm/platform/clock/sam/gclk.hpp.in similarity index 93% rename from src/modm/platform/clock/sam/gclk.hpp rename to src/modm/platform/clock/sam/gclk.hpp.in index 84d25abfa7..8842c53af5 100644 --- a/src/modm/platform/clock/sam/gclk.hpp +++ b/src/modm/platform/clock/sam/gclk.hpp.in @@ -21,6 +21,7 @@ namespace modm::platform /// @ingroup modm_platform_gclk /// @{ +%% if device_family == "d2x" enum class ClockSource : uint32_t { @@ -83,6 +84,7 @@ ClockPeripheral : uint32_t I2s1 = GCLK_CLKCTRL_ID_I2S_1_Val }; /// @} +%% endif /** * Clock management @@ -92,16 +94,17 @@ ClockPeripheral : uint32_t class GenericClockController { public: - static constexpr uint32_t BootFrequency = 1'000'000; + static constexpr uint32_t BootFrequency = {{ boot_frequency }}; - template< uint32_t Core_Hz> + template< uint32_t Core_Hz, uint16_t Vdd_mV=3300 > static uint32_t setFlashLatency(); - template< uint32_t Core_Hz > + template< uint32_t Core_Hz > static void updateCoreFrequency(); +%% if device_family == "d2x" static bool initOsc8MHz(uint32_t waitCycles = 2048); @@ -119,7 +122,6 @@ class GenericClockController template< ClockPeripheral peripheral > static void connect(ClockGenerator clockGen); - private: enum class @@ -127,6 +129,7 @@ class GenericClockController { DFLL48M = 0, }; +%% endif }; } diff --git a/src/modm/platform/clock/sam/gclk_impl.hpp.in b/src/modm/platform/clock/sam/gclk_impl.hpp.in index 32485f9bbc..1f2907a258 100644 --- a/src/modm/platform/clock/sam/gclk_impl.hpp.in +++ b/src/modm/platform/clock/sam/gclk_impl.hpp.in @@ -2,6 +2,7 @@ * Copyright (c) 2019, Ethan Slattery * Copyright (c) 2020, Erik Henriksson * Copyright (c) 2021, Niklas Hauser + * Copyright (c) 2022, Christopher Durand * * This file is part of the modm project. * @@ -13,6 +14,8 @@ #include #include +#include +#include namespace modm::platform { @@ -27,19 +30,41 @@ GenericClockController::updateCoreFrequency() delay_ns_per_loop = computeDelayNsPerLoop(Core_Hz); } -template< uint32_t Core_Hz > +template< uint32_t Core_Hz, uint16_t Vdd_mV=3300 > uint32_t GenericClockController::setFlashLatency() { +%% if device_family == "e5x": +{% raw %} + // TODO: move to device files + constexpr std::array, 6> waitStates0{{ + {22_MHz, 0}, { 44_MHz, 1}, { 67_MHz, 2}, + {89_MHz, 3}, {111_MHz, 4}, {120_MHz, 5} + }}; + constexpr std::array, 6> waitStates1{{ + { 24_MHz, 0}, { 51_MHz, 1}, { 77_MHz, 2}, + {101_MHz, 3}, {119_MHz, 4}, {120_MHz, 5} + }}; +{% endraw %} + constexpr auto waitStates = (Vdd_mV >= 2700) ? waitStates1 : waitStates0; + constexpr auto rws = std::lower_bound(std::begin(waitStates), std::end(waitStates), Core_Hz, + [](auto w1, auto w2) { + return w1.first < w2; + })->second; + NVMCTRL->CTRLA.bit.RWS = rws; + NVMCTRL->CTRLA.bit.AUTOWS = 0; +%% else // See table 41.11 (NVM Characteristics) in the datasheet if constexpr (Core_Hz > 24_MHz) { NVMCTRL->CTRLB.bit.RWS = NVMCTRL_CTRLB_RWS_HALF_Val; } else { NVMCTRL->CTRLB.bit.RWS = NVMCTRL_CTRLB_RWS_SINGLE_Val; } +%% endif return Core_Hz; } +%% if device_family == "d2x" template< ClockPeripheral peripheral > void GenericClockController::connect(ClockGenerator clockGen) @@ -49,6 +74,6 @@ GenericClockController::connect(ClockGenerator clockGen) GCLK_CLKCTRL_GEN(uint32_t(clockGen)) | GCLK_CLKCTRL_ID(uint32_t(peripheral)); } - +%% endif } diff --git a/src/modm/platform/clock/sam/module.lb b/src/modm/platform/clock/sam/module.lb index f68cb6aa3f..a6d1c1f206 100644 --- a/src/modm/platform/clock/sam/module.lb +++ b/src/modm/platform/clock/sam/module.lb @@ -3,6 +3,7 @@ # # Copyright (c) 2016-2018, Niklas Hauser # Copyright (c) 2017, Fabian Greif +# Copyright (c) 2022, Christopher Durand # # This file is part of the modm project. # @@ -19,11 +20,30 @@ def prepare(module, options): if not options[":target"].has_driver("gclk:sam"): return False - module.depends(":cmsis:device", ":architecture:delay") + module.depends(":cmsis:device", ":architecture:delay", ":platform:clock") return True def build(env): + target = env[":target"].identifier + + if target.family in ["d", "e"] and target.series.startswith("5"): + device_family = "e5x" + elif target.family == "d" and target.series.startswith("2"): + device_family = "d2x" + else: + raise RuntimeError("Unsupported device") + + if device_family == "e5x": + boot_frequency = "48'000'000" + else: # d2x + boot_frequency = "1'000'000" + + env.substitutions = { + "target": target, + "boot_frequency": boot_frequency, + "device_family": device_family + } env.outbasepath = "modm/src/modm/platform/clock" - env.copy("gclk.hpp") + env.template("gclk.hpp.in") env.template("gclk.cpp.in") env.template("gclk_impl.hpp.in") From 316ba50eb021851c4f19d49c4518bd5c3c36493f Mon Sep 17 00:00:00 2001 From: Christopher Durand Date: Thu, 3 Feb 2022 13:27:22 +0100 Subject: [PATCH 04/35] [sam] Rename UART drivers The current "samg" driver is very common among SAM devices and is renamed to "sam". The SERCOM UART driver is renamed to "sam-sercom". --- .../uart/{samg => sam-sercom}/module.lb | 30 ++-- src/modm/platform/uart/sam-sercom/uart.cpp.in | 107 +++++++++++++++ src/modm/platform/uart/sam-sercom/uart.hpp.in | 100 ++++++++++++++ .../uart/{sam => sam-sercom}/uart_base.hpp.in | 0 .../uart/{sam => sam-sercom}/uart_hal.hpp.in | 0 .../{sam => sam-sercom}/uart_hal_impl.hpp.in | 0 src/modm/platform/uart/sam/module.lb | 30 ++-- src/modm/platform/uart/sam/uart.cpp.in | 128 ++++++++++-------- src/modm/platform/uart/sam/uart.hpp.in | 104 +++++++------- .../platform/uart/{samg => sam}/uart_base.hpp | 0 src/modm/platform/uart/samg/uart.cpp.in | 127 ----------------- src/modm/platform/uart/samg/uart.hpp.in | 106 --------------- 12 files changed, 366 insertions(+), 366 deletions(-) rename src/modm/platform/uart/{samg => sam-sercom}/module.lb (68%) create mode 100644 src/modm/platform/uart/sam-sercom/uart.cpp.in create mode 100644 src/modm/platform/uart/sam-sercom/uart.hpp.in rename src/modm/platform/uart/{sam => sam-sercom}/uart_base.hpp.in (100%) rename src/modm/platform/uart/{sam => sam-sercom}/uart_hal.hpp.in (100%) rename src/modm/platform/uart/{sam => sam-sercom}/uart_hal_impl.hpp.in (100%) rename src/modm/platform/uart/{samg => sam}/uart_base.hpp (100%) delete mode 100644 src/modm/platform/uart/samg/uart.cpp.in delete mode 100644 src/modm/platform/uart/samg/uart.hpp.in diff --git a/src/modm/platform/uart/samg/module.lb b/src/modm/platform/uart/sam-sercom/module.lb similarity index 68% rename from src/modm/platform/uart/samg/module.lb rename to src/modm/platform/uart/sam-sercom/module.lb index 21747d916c..853f0184c4 100644 --- a/src/modm/platform/uart/samg/module.lb +++ b/src/modm/platform/uart/sam-sercom/module.lb @@ -1,7 +1,7 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- # -# Copyright (c) 2021, Jeff McBride +# Copyright (c) 2020, Erik Henriksson # # This file is part of the modm project. # @@ -22,42 +22,30 @@ class Instance(Module): module.description = "Instance {}".format(self.instance) def prepare(self, module, options): - module.depends(":platform:uart") - - module.add_option( - NumericOption( - name="buffer.tx", - description="Size of transmit buffer", - minimum=1, maximum="64Ki-2", - default=64)) - module.add_option( - NumericOption( - name="buffer.rx", - description="Size of receive buffer", - minimum=1, maximum="64Ki-2", - default=64)) - return True def build(self, env): device = env[":target"].identifier global props props["id"] = self.instance + props["sercom_name"] = self.driver["name"].capitalize() env.substitutions = props env.outbasepath = "modm/src/modm/platform/uart" + env.template("uart_hal.hpp.in", "uart_hal_{}.hpp".format(self.instance)) + env.template("uart_hal_impl.hpp.in", "uart_hal_{}_impl.hpp".format(self.instance)) env.template("uart.hpp.in", "uart_{}.hpp".format(self.instance)) env.template("uart.cpp.in", "uart_{}.cpp".format(self.instance)) def init(module): module.name = ":platform:uart" - module.description = "Universal Synchronous Asynchronous Receiver Transmitter (UART)" + module.description = "Universal Asynchronous Receiver Transmitter (UART)" def prepare(module, options): device = options[":target"] - if not (device.has_driver("usart:samg*")): + if not (device.has_driver("sercom:sam")): return False module.depends( @@ -65,10 +53,10 @@ def prepare(module, options): ":math:algorithm", ":cmsis:device", ":platform:gpio", - ":platform:clockgen") + ":platform:gclk") global props - drivers = options[":target"].get_all_drivers("usart") + drivers = options[":target"].get_all_drivers("sercom") for driver in drivers: for instance in driver["instance"]: module.add_submodule(Instance(driver, instance)) @@ -80,4 +68,4 @@ def build(env): global props env.substitutions = props env.outbasepath = "modm/src/modm/platform/uart" - env.copy("uart_base.hpp") + env.template("uart_base.hpp.in") diff --git a/src/modm/platform/uart/sam-sercom/uart.cpp.in b/src/modm/platform/uart/sam-sercom/uart.cpp.in new file mode 100644 index 0000000000..1c527e4535 --- /dev/null +++ b/src/modm/platform/uart/sam-sercom/uart.cpp.in @@ -0,0 +1,107 @@ +/* + * 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 name = "Uart" ~ id +%% set hal = "UartHal" ~ id + +#include "../device.hpp" +#include "uart_hal_{{ id }}.hpp" +#include "uart_{{ id }}.hpp" + +namespace modm::platform +{ + +void +{{ name }}::writeBlocking(uint8_t data) +{ + while(!{{ hal }}::isTransmitRegisterEmpty()); + {{ hal }}::write(data); +} + +void +{{ name }}::writeBlocking(const uint8_t *data, std::size_t length) +{ + while (length-- != 0) { + writeBlocking(*data++); + } +} + +void +{{ name }}::flushWriteBuffer() +{ + return; +} + +bool +{{ name }}::write(uint8_t data) +{ + if({{ hal }}::isTransmitRegisterEmpty()) { + {{ hal }}::write(data); + return true; + } else { + return false; + } +} + +std::size_t +{{ name }}::write(const uint8_t *data, std::size_t length) +{ + uint32_t i = 0; + for (; i < length; ++i) + { + if (!write(*data++)) { + return i; + } + } + return i; +} + +bool +{{ name }}::isWriteFinished() +{ + return {{ hal }}::isTransmitRegisterEmpty(); +} + +std::size_t +{{ name }}::discardTransmitBuffer() +{ + return 0; +} + +bool +{{ name }}::read(uint8_t &data) +{ + if({{ hal }}::isReceiveRegisterNotEmpty()) { + {{ hal }}::read(data); + return true; + } else { + return false; + } +} + +std::size_t +{{ name }}::read(uint8_t *data, std::size_t length) +{ + (void)length; // avoid compiler warning + if(read(*data)) { + return 1; + } else { + return 0; + } +} + +std::size_t +{{ name }}::discardReceiveBuffer() +{ + return 0; +} + +} // namespace modm::platform diff --git a/src/modm/platform/uart/sam-sercom/uart.hpp.in b/src/modm/platform/uart/sam-sercom/uart.hpp.in new file mode 100644 index 0000000000..56e4a3f424 --- /dev/null +++ b/src/modm/platform/uart/sam-sercom/uart.hpp.in @@ -0,0 +1,100 @@ +/* + * 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 hal = "UartHal" ~ id +%% set name = "Uart" ~ id + +#pragma once + +#include +#include "uart_base.hpp" +#include "uart_hal_{{ id }}.hpp" +#include + +namespace modm::platform +{ + +/** + * Universal asynchronous receiver transmitter ({{ "Uart" | upper ~ id }}) + * + * @author Erik Henriksson + * @ingroup modm_platform_uart modm_platform_uart_{{id}} + */ +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< class... Pins > + static void + 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) > + static void + initialize(Parity parity = Parity::Disabled) + { + {{ hal }}::initialize(parity); + {{ hal }}::setTransmitterEnable(true); + {{ hal }}::setReceiverEnable(true); + } + + static void + writeBlocking(uint8_t data); + + static void + writeBlocking(const uint8_t *data, std::size_t length); + + static void + flushWriteBuffer(); + + static bool + write(uint8_t data); + + static std::size_t + write(const uint8_t *data, std::size_t length); + + static bool + isWriteFinished(); + + static std::size_t + discardTransmitBuffer(); + + static bool + read(uint8_t &data); + + static std::size_t + read(uint8_t *buffer, std::size_t length); + + static std::size_t + discardReceiveBuffer(); +}; + +} // namespace modm::platform diff --git a/src/modm/platform/uart/sam/uart_base.hpp.in b/src/modm/platform/uart/sam-sercom/uart_base.hpp.in similarity index 100% rename from src/modm/platform/uart/sam/uart_base.hpp.in rename to src/modm/platform/uart/sam-sercom/uart_base.hpp.in diff --git a/src/modm/platform/uart/sam/uart_hal.hpp.in b/src/modm/platform/uart/sam-sercom/uart_hal.hpp.in similarity index 100% rename from src/modm/platform/uart/sam/uart_hal.hpp.in rename to src/modm/platform/uart/sam-sercom/uart_hal.hpp.in diff --git a/src/modm/platform/uart/sam/uart_hal_impl.hpp.in b/src/modm/platform/uart/sam-sercom/uart_hal_impl.hpp.in similarity index 100% rename from src/modm/platform/uart/sam/uart_hal_impl.hpp.in rename to src/modm/platform/uart/sam-sercom/uart_hal_impl.hpp.in diff --git a/src/modm/platform/uart/sam/module.lb b/src/modm/platform/uart/sam/module.lb index 853f0184c4..21747d916c 100644 --- a/src/modm/platform/uart/sam/module.lb +++ b/src/modm/platform/uart/sam/module.lb @@ -1,7 +1,7 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- # -# Copyright (c) 2020, Erik Henriksson +# Copyright (c) 2021, Jeff McBride # # This file is part of the modm project. # @@ -22,30 +22,42 @@ class Instance(Module): module.description = "Instance {}".format(self.instance) def prepare(self, module, options): + module.depends(":platform:uart") + + module.add_option( + NumericOption( + name="buffer.tx", + description="Size of transmit buffer", + minimum=1, maximum="64Ki-2", + default=64)) + module.add_option( + NumericOption( + name="buffer.rx", + description="Size of receive buffer", + minimum=1, maximum="64Ki-2", + default=64)) + return True def build(self, env): device = env[":target"].identifier global props props["id"] = self.instance - props["sercom_name"] = self.driver["name"].capitalize() env.substitutions = props env.outbasepath = "modm/src/modm/platform/uart" - env.template("uart_hal.hpp.in", "uart_hal_{}.hpp".format(self.instance)) - env.template("uart_hal_impl.hpp.in", "uart_hal_{}_impl.hpp".format(self.instance)) env.template("uart.hpp.in", "uart_{}.hpp".format(self.instance)) env.template("uart.cpp.in", "uart_{}.cpp".format(self.instance)) def init(module): module.name = ":platform:uart" - module.description = "Universal Asynchronous Receiver Transmitter (UART)" + module.description = "Universal Synchronous Asynchronous Receiver Transmitter (UART)" def prepare(module, options): device = options[":target"] - if not (device.has_driver("sercom:sam")): + if not (device.has_driver("usart:samg*")): return False module.depends( @@ -53,10 +65,10 @@ def prepare(module, options): ":math:algorithm", ":cmsis:device", ":platform:gpio", - ":platform:gclk") + ":platform:clockgen") global props - drivers = options[":target"].get_all_drivers("sercom") + drivers = options[":target"].get_all_drivers("usart") for driver in drivers: for instance in driver["instance"]: module.add_submodule(Instance(driver, instance)) @@ -68,4 +80,4 @@ def build(env): global props env.substitutions = props env.outbasepath = "modm/src/modm/platform/uart" - env.template("uart_base.hpp.in") + env.copy("uart_base.hpp") diff --git a/src/modm/platform/uart/sam/uart.cpp.in b/src/modm/platform/uart/sam/uart.cpp.in index 1c527e4535..d3462c082d 100644 --- a/src/modm/platform/uart/sam/uart.cpp.in +++ b/src/modm/platform/uart/sam/uart.cpp.in @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Erik Henriksson + * Copyright (c) 2021, Jeff McBride * * This file is part of the modm project. * @@ -9,99 +9,119 @@ */ // ---------------------------------------------------------------------------- -%% set name = "Uart" ~ id -%% set hal = "UartHal" ~ id - -#include "../device.hpp" -#include "uart_hal_{{ id }}.hpp" #include "uart_{{ id }}.hpp" -namespace modm::platform -{ +#include -void -{{ name }}::writeBlocking(uint8_t data) +namespace { - while(!{{ hal }}::isTransmitRegisterEmpty()); - {{ hal }}::write(data); + static modm::atomic::Queue rxBuffer; + static modm::atomic::Queue txBuffer; } -void -{{ name }}::writeBlocking(const uint8_t *data, std::size_t length) +MODM_ISR(FLEXCOM{{ id }}) { - while (length-- != 0) { - writeBlocking(*data++); + using namespace modm::platform; + if(Uart{{ id }}::isReceiveReady()) { + uint8_t data = (uint8_t)USART{{ id }}->US_RHR; + Uart{{ id }}::read(data); + rxBuffer.push(data); + } + + if(Uart{{ id }}::isTransmitReady()) { + if(txBuffer.isEmpty()) { + USART{{ id }}->US_IDR = US_IDR_TXRDY; + } else { + USART{{ id }}->US_THR = txBuffer.get(); + txBuffer.pop(); + } } } -void -{{ name }}::flushWriteBuffer() +namespace modm::platform { - return; -} bool -{{ name }}::write(uint8_t data) -{ - if({{ hal }}::isTransmitRegisterEmpty()) { - {{ hal }}::write(data); - return true; - } else { +Uart{{ id }}::read(uint8_t &dataOut) { + if(rxBuffer.isEmpty()) { return false; + } else { + dataOut = rxBuffer.get(); + rxBuffer.pop(); + return true; } } std::size_t -{{ name }}::write(const uint8_t *data, std::size_t length) -{ +Uart{{ id }}::read(uint8_t *data, std::size_t length) { uint32_t i = 0; - for (; i < length; ++i) - { - if (!write(*data++)) { + for(; i < length; i++) { + if(rxBuffer.isEmpty()) { return i; + } else { + data[i] = rxBuffer.get(); + rxBuffer.pop(); } } return i; } bool -{{ name }}::isWriteFinished() +Uart{{ id }}::write(uint8_t data) { - return {{ hal }}::isTransmitRegisterEmpty(); + if(txBuffer.isEmpty() && isTransmitReady()) { + USART{{ id }}->US_THR = data; + } else { + if(!txBuffer.push(data)) { + return false; + } + // Enable tx interrupt + USART{{ id }}->US_IER = US_IER_TXRDY; + } + return true; } std::size_t -{{ name }}::discardTransmitBuffer() +Uart{{ id }}::write(const uint8_t *data, std::size_t length) { - return 0; + uint32_t i = 0; + for(; i < length; i++) { + if(!write(data[i])) { + return i; + } + } + return i; } bool -{{ name }}::read(uint8_t &data) +Uart{{ id }}::isWriteFinished() { - if({{ hal }}::isReceiveRegisterNotEmpty()) { - {{ hal }}::read(data); - return true; - } else { - return false; - } + return txBuffer.isEmpty() && isTransmitReady(); } -std::size_t -{{ name }}::read(uint8_t *data, std::size_t length) +void +Uart{{ id }}::flushWriteBuffer() { - (void)length; // avoid compiler warning - if(read(*data)) { - return 1; - } else { - return 0; - } + while(!isWriteFinished()); } -std::size_t -{{ name }}::discardReceiveBuffer() +void +Uart{{ id }}::setParity(Parity parity) +{ + USART{{ id }}->US_MR = (USART{{ id }}->US_MR & ~US_MR_PAR_Msk) | (uint32_t)parity; +} + +void +Uart{{ id }}::setWordLength(WordLength length) { - return 0; + if(length == WordLength::Bit9) { + USART{{ id }}->US_MR |= US_MR_MODE9; + } else { + USART{{ id }}->US_MR &= ~US_MR_MODE9; + USART{{ id }}->US_MR = + (USART{{ id }}->US_MR & ~US_MR_CHRL_Msk) + | US_MR_CHRL((uint32_t)length); + } } -} // namespace modm::platform +} // namespace modm::platform \ No newline at end of file diff --git a/src/modm/platform/uart/sam/uart.hpp.in b/src/modm/platform/uart/sam/uart.hpp.in index 56e4a3f424..93b394f596 100644 --- a/src/modm/platform/uart/sam/uart.hpp.in +++ b/src/modm/platform/uart/sam/uart.hpp.in @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Erik Henriksson + * Copyright (c) 2021, Jeff McBride * * This file is part of the modm project. * @@ -9,37 +9,29 @@ */ // ---------------------------------------------------------------------------- -%% set hal = "UartHal" ~ id -%% set name = "Uart" ~ id - #pragma once -#include #include "uart_base.hpp" -#include "uart_hal_{{ id }}.hpp" -#include +#include +#include +#include +#include namespace modm::platform { /** - * Universal asynchronous receiver transmitter ({{ "Uart" | upper ~ id }}) + * Universal synchronous asynchronous receiver transmitter (USART{{ id }}) * - * @author Erik Henriksson + * @author Jeff McBride * @ingroup modm_platform_uart modm_platform_uart_{{id}} */ -class {{ name }} : public UartBase, public ::modm::Uart +class Uart{{ id }} : 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: + static constexpr size_t RxBufferSize = {{ options["buffer.rx"] }}; + static constexpr size_t TxBufferSize = {{ options["buffer.tx"] }}; + template< class... Pins > static void connect() @@ -49,52 +41,66 @@ public: 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 {}; + using Flexcom = Peripherals::Flexcom<{{ id | int }}>; + using RxConnector = typename RxPin::template Connector; + using TxConnector = typename TxPin::template Connector; RxConnector::connect(); TxConnector::connect(); } + template< class SystemClock, baudrate_t baudrate, percent_t tolerance=pct(1) > - static void - initialize(Parity parity = Parity::Disabled) + static inline void + initialize( + Parity parity=Parity::Disabled, + WordLength length=WordLength::Bit8, + uint8_t irq_priority = 5) { - {{ hal }}::initialize(parity); - {{ hal }}::setTransmitterEnable(true); - {{ hal }}::setReceiverEnable(true); + ClockGen::enable(); + FLEXCOM{{ id }}->FLEXCOM_MR = FLEXCOM_MR_OPMODE_USART; + constexpr auto result = Prescaler::from_function( + SystemClock::Mck, + baudrate, + 1, + 65535, + [](uint32_t x) { return x * 8; } + ); + + USART{{ id }}->US_BRGR = result.index; + + // Use 8x oversampling (this affects baud rate generation) + USART{{ id }}->US_MR = US_MR_OVER; + + setParity(parity); + setWordLength(length); + + USART{{ id }}->US_CR = US_CR_RXEN | US_CR_TXEN; + + // Enable the IRQ + + NVIC_SetPriority(FLEXCOM{{ id }}_IRQn, irq_priority); + NVIC_EnableIRQ(FLEXCOM{{ id }}_IRQn); } - static void - writeBlocking(uint8_t data); + static bool read(uint8_t &dataOut); - static void - writeBlocking(const uint8_t *data, std::size_t length); + static std::size_t read(uint8_t *data, std::size_t length); - static void - flushWriteBuffer(); + static bool write(uint8_t data); - static bool - write(uint8_t data); + static std::size_t write(const uint8_t *data, std::size_t length); - static std::size_t - write(const uint8_t *data, std::size_t length); + static bool isWriteFinished(); - static bool - isWriteFinished(); + static void flushWriteBuffer(); - static std::size_t - discardTransmitBuffer(); + static void setParity(Parity parity); - static bool - read(uint8_t &data); + static void setWordLength(WordLength length); - static std::size_t - read(uint8_t *buffer, std::size_t length); + static inline bool isTransmitReady() { return USART{{ id }}->US_CSR & US_CSR_TXRDY; } - static std::size_t - discardReceiveBuffer(); + static inline bool isReceiveReady() { return USART{{ id }}->US_CSR & US_CSR_RXRDY; } }; -} // namespace modm::platform +} // namespace modm::platform diff --git a/src/modm/platform/uart/samg/uart_base.hpp b/src/modm/platform/uart/sam/uart_base.hpp similarity index 100% rename from src/modm/platform/uart/samg/uart_base.hpp rename to src/modm/platform/uart/sam/uart_base.hpp diff --git a/src/modm/platform/uart/samg/uart.cpp.in b/src/modm/platform/uart/samg/uart.cpp.in deleted file mode 100644 index d3462c082d..0000000000 --- a/src/modm/platform/uart/samg/uart.cpp.in +++ /dev/null @@ -1,127 +0,0 @@ -/* - * 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 "uart_{{ id }}.hpp" - -#include - -namespace -{ - static modm::atomic::Queue rxBuffer; - static modm::atomic::Queue txBuffer; -} - -MODM_ISR(FLEXCOM{{ id }}) -{ - using namespace modm::platform; - if(Uart{{ id }}::isReceiveReady()) { - uint8_t data = (uint8_t)USART{{ id }}->US_RHR; - Uart{{ id }}::read(data); - rxBuffer.push(data); - } - - if(Uart{{ id }}::isTransmitReady()) { - if(txBuffer.isEmpty()) { - USART{{ id }}->US_IDR = US_IDR_TXRDY; - } else { - USART{{ id }}->US_THR = txBuffer.get(); - txBuffer.pop(); - } - } -} - -namespace modm::platform -{ - -bool -Uart{{ id }}::read(uint8_t &dataOut) { - if(rxBuffer.isEmpty()) { - return false; - } else { - dataOut = rxBuffer.get(); - rxBuffer.pop(); - return true; - } -} - -std::size_t -Uart{{ id }}::read(uint8_t *data, std::size_t length) { - uint32_t i = 0; - for(; i < length; i++) { - if(rxBuffer.isEmpty()) { - return i; - } else { - data[i] = rxBuffer.get(); - rxBuffer.pop(); - } - } - return i; -} - -bool -Uart{{ id }}::write(uint8_t data) -{ - if(txBuffer.isEmpty() && isTransmitReady()) { - USART{{ id }}->US_THR = data; - } else { - if(!txBuffer.push(data)) { - return false; - } - // Enable tx interrupt - USART{{ id }}->US_IER = US_IER_TXRDY; - } - return true; -} - -std::size_t -Uart{{ id }}::write(const uint8_t *data, std::size_t length) -{ - uint32_t i = 0; - for(; i < length; i++) { - if(!write(data[i])) { - return i; - } - } - return i; -} - -bool -Uart{{ id }}::isWriteFinished() -{ - return txBuffer.isEmpty() && isTransmitReady(); -} - -void -Uart{{ id }}::flushWriteBuffer() -{ - while(!isWriteFinished()); -} - -void -Uart{{ id }}::setParity(Parity parity) -{ - USART{{ id }}->US_MR = (USART{{ id }}->US_MR & ~US_MR_PAR_Msk) | (uint32_t)parity; -} - -void -Uart{{ id }}::setWordLength(WordLength length) -{ - if(length == WordLength::Bit9) { - USART{{ id }}->US_MR |= US_MR_MODE9; - } else { - USART{{ id }}->US_MR &= ~US_MR_MODE9; - USART{{ id }}->US_MR = - (USART{{ id }}->US_MR & ~US_MR_CHRL_Msk) - | US_MR_CHRL((uint32_t)length); - } -} - -} // namespace modm::platform \ No newline at end of file diff --git a/src/modm/platform/uart/samg/uart.hpp.in b/src/modm/platform/uart/samg/uart.hpp.in deleted file mode 100644 index 93b394f596..0000000000 --- a/src/modm/platform/uart/samg/uart.hpp.in +++ /dev/null @@ -1,106 +0,0 @@ -/* - * 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/. - */ -// ---------------------------------------------------------------------------- - -#pragma once - -#include "uart_base.hpp" -#include -#include -#include -#include - -namespace modm::platform -{ - -/** - * Universal synchronous asynchronous receiver transmitter (USART{{ id }}) - * - * @author Jeff McBride - * @ingroup modm_platform_uart modm_platform_uart_{{id}} - */ -class Uart{{ id }} : public UartBase, public modm::Uart -{ -public: - static constexpr size_t RxBufferSize = {{ options["buffer.rx"] }}; - static constexpr size_t TxBufferSize = {{ options["buffer.tx"] }}; - - template< class... Pins > - static void - connect() - { - using RxPin = GetPin_t; - using TxPin = GetPin_t; - static_assert( - !std::is_same_v, - "Rx and Tx cannot use the same pin!"); - using Flexcom = Peripherals::Flexcom<{{ id | int }}>; - using RxConnector = typename RxPin::template Connector; - using TxConnector = typename TxPin::template Connector; - RxConnector::connect(); - TxConnector::connect(); - } - - - template< class SystemClock, baudrate_t baudrate, percent_t tolerance=pct(1) > - static inline void - initialize( - Parity parity=Parity::Disabled, - WordLength length=WordLength::Bit8, - uint8_t irq_priority = 5) - { - ClockGen::enable(); - FLEXCOM{{ id }}->FLEXCOM_MR = FLEXCOM_MR_OPMODE_USART; - constexpr auto result = Prescaler::from_function( - SystemClock::Mck, - baudrate, - 1, - 65535, - [](uint32_t x) { return x * 8; } - ); - - USART{{ id }}->US_BRGR = result.index; - - // Use 8x oversampling (this affects baud rate generation) - USART{{ id }}->US_MR = US_MR_OVER; - - setParity(parity); - setWordLength(length); - - USART{{ id }}->US_CR = US_CR_RXEN | US_CR_TXEN; - - // Enable the IRQ - - NVIC_SetPriority(FLEXCOM{{ id }}_IRQn, irq_priority); - NVIC_EnableIRQ(FLEXCOM{{ id }}_IRQn); - } - - static bool read(uint8_t &dataOut); - - static std::size_t read(uint8_t *data, std::size_t length); - - static bool write(uint8_t data); - - static std::size_t write(const uint8_t *data, std::size_t length); - - static bool isWriteFinished(); - - static void flushWriteBuffer(); - - static void setParity(Parity parity); - - static void setWordLength(WordLength length); - - static inline bool isTransmitReady() { return USART{{ id }}->US_CSR & US_CSR_TXRDY; } - - static inline bool isReceiveReady() { return USART{{ id }}->US_CSR & US_CSR_RXRDY; } -}; - -} // namespace modm::platform From 460f1892cf8b9187a7977faf24ee1b278a7ae2b4 Mon Sep 17 00:00:00 2001 From: Christopher Durand Date: Sat, 5 Feb 2022 00:38:03 +0100 Subject: [PATCH 05/35] [sam] Add SAMx7x U(S)ART support, fix data reception SAMx7x devices feature both UART and USART peripherals with the same id. The driver will provide `:platform:uart:*` modules for UART instances and `:platform:usart:*` modules for USART instances. Fixes receiving data by enabling the RX interrupt. **WARNING**, this is a breaking change. For the sake of consistency, also SAMG devices, which have had a USART peripheral provided as `UartX` with module `:platform:uart:*`, will use the USART naming. Furthermore, the clock source has to be specified as `U(s)art*` in `SystemClock` to allow to configure it to sources different to `Mclk`. --- README.md | 2 +- src/modm/board/samg55_xplained_pro/board.hpp | 4 +- src/modm/board/samg55_xplained_pro/module.lb | 4 +- src/modm/platform/uart/sam/uart.cpp.in | 56 ++++++------ src/modm/platform/uart/sam/uart.hpp.in | 74 ++++++++++++---- .../platform/uart/sam/{ => uart}/module.lb | 36 ++++---- .../sam/{uart_base.hpp => uart_base.hpp.in} | 4 +- src/modm/platform/uart/sam/usart/module.lb | 88 +++++++++++++++++++ tools/scripts/generate_hal_matrix.py | 1 + 9 files changed, 206 insertions(+), 63 deletions(-) rename src/modm/platform/uart/sam/{ => uart}/module.lb (70%) rename src/modm/platform/uart/sam/{uart_base.hpp => uart_base.hpp.in} (94%) create mode 100644 src/modm/platform/uart/sam/usart/module.lb diff --git a/README.md b/README.md index f12b1d9c64..f1189a1773 100644 --- a/README.md +++ b/README.md @@ -475,7 +475,7 @@ Please [discover modm's peripheral drivers for your specific device][discover]. ✅ ✅ ✅ -○ +✅ ✅ ✅ ✅ diff --git a/src/modm/board/samg55_xplained_pro/board.hpp b/src/modm/board/samg55_xplained_pro/board.hpp index 55be67fed6..1d9c0628e0 100644 --- a/src/modm/board/samg55_xplained_pro/board.hpp +++ b/src/modm/board/samg55_xplained_pro/board.hpp @@ -39,6 +39,8 @@ struct SystemClock static constexpr uint32_t Pck6 = Mck; static constexpr uint32_t Pck7 = Mck; + static constexpr uint32_t Usart7 = Mck; + static bool inline enable() { @@ -62,7 +64,7 @@ struct SystemClock using Led = GpioA6; using Button = GpioA2; -using DebugUart = Uart7; +using DebugUart = Usart7; using TxPin = GpioA28; using RxPin = GpioA27; diff --git a/src/modm/board/samg55_xplained_pro/module.lb b/src/modm/board/samg55_xplained_pro/module.lb index b3302f866c..3aec8017fb 100644 --- a/src/modm/board/samg55_xplained_pro/module.lb +++ b/src/modm/board/samg55_xplained_pro/module.lb @@ -20,7 +20,7 @@ def prepare(module, options): module.depends( ":platform:clockgen", - ":platform:uart:7", + ":platform:usart:7", ":platform:gpio", ":platform:core", ":platform:usb", @@ -31,4 +31,4 @@ def build(env): env.outbasepath = "modm/src/modm/board" env.copy('board.hpp') - # TODO: openocd config? \ No newline at end of file + # TODO: openocd config? diff --git a/src/modm/platform/uart/sam/uart.cpp.in b/src/modm/platform/uart/sam/uart.cpp.in index d3462c082d..cc5a4898f0 100644 --- a/src/modm/platform/uart/sam/uart.cpp.in +++ b/src/modm/platform/uart/sam/uart.cpp.in @@ -1,5 +1,6 @@ /* * Copyright (c) 2021, Jeff McBride + * Copyright (c) 2022, Christopher Durand * * This file is part of the modm project. * @@ -9,30 +10,33 @@ */ // ---------------------------------------------------------------------------- -#include "uart_{{ id }}.hpp" +#include "{{ type }}_{{ id }}.hpp" #include +%% set name="{}{}".format(type.capitalize(), id) +%% set reg=name.upper() + namespace { static modm::atomic::Queue rxBuffer; static modm::atomic::Queue txBuffer; } -MODM_ISR(FLEXCOM{{ id }}) +MODM_ISR({{ peripheral | upper }}{{ id }}) { using namespace modm::platform; - if(Uart{{ id }}::isReceiveReady()) { - uint8_t data = (uint8_t)USART{{ id }}->US_RHR; - Uart{{ id }}::read(data); + if({{ name }}::isReceiveReady()) { + uint8_t data = (uint8_t){{ name }}::Regs()->{{ prefix }}_RHR; + {{ name }}::read(data); rxBuffer.push(data); } - if(Uart{{ id }}::isTransmitReady()) { + if({{ name }}::isTransmitReady()) { if(txBuffer.isEmpty()) { - USART{{ id }}->US_IDR = US_IDR_TXRDY; + {{ name }}::Regs()->{{ prefix }}_IDR = {{ prefix }}_IDR_TXRDY; } else { - USART{{ id }}->US_THR = txBuffer.get(); + {{ name }}::Regs()->{{ prefix }}_THR = txBuffer.get(); txBuffer.pop(); } } @@ -42,7 +46,7 @@ namespace modm::platform { bool -Uart{{ id }}::read(uint8_t &dataOut) { +{{ name }}::read(uint8_t &dataOut) { if(rxBuffer.isEmpty()) { return false; } else { @@ -53,7 +57,7 @@ Uart{{ id }}::read(uint8_t &dataOut) { } std::size_t -Uart{{ id }}::read(uint8_t *data, std::size_t length) { +{{ name }}::read(uint8_t *data, std::size_t length) { uint32_t i = 0; for(; i < length; i++) { if(rxBuffer.isEmpty()) { @@ -67,22 +71,22 @@ Uart{{ id }}::read(uint8_t *data, std::size_t length) { } bool -Uart{{ id }}::write(uint8_t data) +{{ name }}::write(uint8_t data) { if(txBuffer.isEmpty() && isTransmitReady()) { - USART{{ id }}->US_THR = data; + Regs()->{{ prefix }}_THR = data; } else { if(!txBuffer.push(data)) { return false; } // Enable tx interrupt - USART{{ id }}->US_IER = US_IER_TXRDY; + Regs()->{{ prefix }}_IER = {{ prefix }}_IER_TXRDY; } return true; } std::size_t -Uart{{ id }}::write(const uint8_t *data, std::size_t length) +{{ name }}::write(const uint8_t *data, std::size_t length) { uint32_t i = 0; for(; i < length; i++) { @@ -94,34 +98,36 @@ Uart{{ id }}::write(const uint8_t *data, std::size_t length) } bool -Uart{{ id }}::isWriteFinished() +{{ name }}::isWriteFinished() { return txBuffer.isEmpty() && isTransmitReady(); } void -Uart{{ id }}::flushWriteBuffer() +{{ name }}::flushWriteBuffer() { while(!isWriteFinished()); } void -Uart{{ id }}::setParity(Parity parity) +{{ name }}::setParity(Parity parity) { - USART{{ id }}->US_MR = (USART{{ id }}->US_MR & ~US_MR_PAR_Msk) | (uint32_t)parity; + Regs()->{{ prefix }}_MR = (Regs()->{{ prefix }}_MR & ~{{ prefix }}_MR_PAR_Msk) | (uint32_t)parity; } +%% if type == "usart" void -Uart{{ id }}::setWordLength(WordLength length) +{{ name }}::setWordLength(WordLength length) { if(length == WordLength::Bit9) { - USART{{ id }}->US_MR |= US_MR_MODE9; + Regs()->{{ prefix }}_MR |= {{ prefix }}_MR_MODE9; } else { - USART{{ id }}->US_MR &= ~US_MR_MODE9; - USART{{ id }}->US_MR = - (USART{{ id }}->US_MR & ~US_MR_CHRL_Msk) - | US_MR_CHRL((uint32_t)length); + Regs()->{{ prefix }}_MR &= ~{{ prefix }}_MR_MODE9; + Regs()->{{ prefix }}_MR = + (Regs()->{{ prefix }}_MR & ~{{ prefix }}_MR_CHRL_Msk) + | {{ prefix }}_MR_CHRL((uint32_t)length); } } +%% endif -} // namespace modm::platform \ No newline at end of file +} // namespace modm::platform diff --git a/src/modm/platform/uart/sam/uart.hpp.in b/src/modm/platform/uart/sam/uart.hpp.in index 93b394f596..0ad8f4ea4f 100644 --- a/src/modm/platform/uart/sam/uart.hpp.in +++ b/src/modm/platform/uart/sam/uart.hpp.in @@ -1,5 +1,6 @@ /* * Copyright (c) 2021, Jeff McBride + * Copyright (c) 2022, Christopher Durand * * This file is part of the modm project. * @@ -11,23 +12,39 @@ #pragma once -#include "uart_base.hpp" +#include "{{ type }}_base.hpp" #include #include #include #include +%% set name="{}{}".format(type.capitalize(), id) +%% set reg=name.upper() + namespace modm::platform { /** +%% if type == "usart" * Universal synchronous asynchronous receiver transmitter (USART{{ id }}) +%% else + * Universal asynchronous receiver transmitter (UART{{ id }}) +%% endif * * @author Jeff McBride - * @ingroup modm_platform_uart modm_platform_uart_{{id}} + * @author Christopher Durand + * @ingroup modm_platform_{{type}} modm_platform_{{type}}_{{id}} */ -class Uart{{ id }} : public UartBase, public modm::Uart +class {{ name }} : public {{ type }}Base, public modm::Uart { +private: + // prevent name collision between ::Uart* from SAM header with modm::Uart +%% if type == "uart" + static auto* Regs() { return reinterpret_cast<::Uart*>{{ reg }}; } +%% else + static auto* Regs() { return {{ reg }}; } +%% endif + friend void ::{{ peripheral | upper }}{{ id }}_IRQHandler(); public: static constexpr size_t RxBufferSize = {{ options["buffer.rx"] }}; static constexpr size_t TxBufferSize = {{ options["buffer.tx"] }}; @@ -41,9 +58,17 @@ public: static_assert( !std::is_same_v, "Rx and Tx cannot use the same pin!"); - using Flexcom = Peripherals::Flexcom<{{ id | int }}>; - using RxConnector = typename RxPin::template Connector; - using TxConnector = typename TxPin::template Connector; + using Peripheral = Peripherals::{{ peripheral }}<{{ id | int }}>; + %% if peripheral == "Flexcom" + using RxConnector = typename RxPin::template Connector; + using TxConnector = typename TxPin::template Connector; + %% elif type == "usart" + using RxConnector = typename RxPin::template Connector>; + using TxConnector = typename TxPin::template Connector>; + %% elif type == "uart" + using RxConnector = typename RxPin::template Connector>; + using TxConnector = typename TxPin::template Connector>; + %% endif RxConnector::connect(); TxConnector::connect(); } @@ -53,33 +78,46 @@ public: static inline void initialize( Parity parity=Parity::Disabled, +%% if type == "usart" WordLength length=WordLength::Bit8, +%% endif uint8_t irq_priority = 5) { - ClockGen::enable(); + ClockGen::enable(); + +%% if peripheral == "Flexcom" FLEXCOM{{ id }}->FLEXCOM_MR = FLEXCOM_MR_OPMODE_USART; +%% endif constexpr auto result = Prescaler::from_function( - SystemClock::Mck, + SystemClock::{{type | capitalize}}{{id}}, baudrate, 1, 65535, +%% if type == "usart" [](uint32_t x) { return x * 8; } +%% else + [](uint32_t x) { return x * 16; } +%% endif ); - USART{{ id }}->US_BRGR = result.index; + Regs()->{{ prefix }}_BRGR = result.index; +%% if type == "usart" // Use 8x oversampling (this affects baud rate generation) - USART{{ id }}->US_MR = US_MR_OVER; + Regs()->{{ prefix }}_MR = {{ prefix }}_MR_OVER; +%% endif setParity(parity); +%% if type == "usart" setWordLength(length); - - USART{{ id }}->US_CR = US_CR_RXEN | US_CR_TXEN; +%% endif + Regs()->{{ prefix }}_CR = {{ prefix }}_CR_RXEN | {{ prefix }}_CR_TXEN; + // Enable rx interrupt + Regs()->{{ prefix }}_IER = {{ prefix }}_IER_RXRDY; // Enable the IRQ - - NVIC_SetPriority(FLEXCOM{{ id }}_IRQn, irq_priority); - NVIC_EnableIRQ(FLEXCOM{{ id }}_IRQn); + NVIC_SetPriority({{ peripheral | upper }}{{ id }}_IRQn, irq_priority); + NVIC_EnableIRQ({{ peripheral | upper }}{{ id }}_IRQn); } static bool read(uint8_t &dataOut); @@ -96,11 +134,13 @@ public: static void setParity(Parity parity); +%% if type == "usart" static void setWordLength(WordLength length); +%% endif - static inline bool isTransmitReady() { return USART{{ id }}->US_CSR & US_CSR_TXRDY; } + static inline bool isTransmitReady() { return Regs()->{{ prefix }}_{{ sr }} & {{ prefix }}_{{ sr }}_TXRDY; } - static inline bool isReceiveReady() { return USART{{ id }}->US_CSR & US_CSR_RXRDY; } + static inline bool isReceiveReady() { return Regs()->{{ prefix }}_{{ sr }} & {{ prefix }}_{{ sr }}_RXRDY; } }; } // namespace modm::platform diff --git a/src/modm/platform/uart/sam/module.lb b/src/modm/platform/uart/sam/uart/module.lb similarity index 70% rename from src/modm/platform/uart/sam/module.lb rename to src/modm/platform/uart/sam/uart/module.lb index 21747d916c..c66b837bdd 100644 --- a/src/modm/platform/uart/sam/module.lb +++ b/src/modm/platform/uart/sam/uart/module.lb @@ -10,7 +10,16 @@ # file, You can obtain one at http://mozilla.org/MPL/2.0/. # ----------------------------------------------------------------------------- -props = {} +def _get_properties(env, instance=None): + device = env[":target"] + return { + "type" : "uart", + "peripheral" : "Uart", + "id" : instance, + "prefix" : "UART", + "sr" : "SR" + } + class Instance(Module): def __init__(self, driver, instance): @@ -40,24 +49,21 @@ class Instance(Module): return True def build(self, env): - device = env[":target"].identifier - global props - props["id"] = self.instance - - env.substitutions = props + env.substitutions = _get_properties(env, self.instance) env.outbasepath = "modm/src/modm/platform/uart" - env.template("uart.hpp.in", "uart_{}.hpp".format(self.instance)) - env.template("uart.cpp.in", "uart_{}.cpp".format(self.instance)) + env.template("../uart.hpp.in", "uart_{}.hpp".format(self.instance)) + env.template("../uart.cpp.in", "uart_{}.cpp".format(self.instance)) def init(module): module.name = ":platform:uart" - module.description = "Universal Synchronous Asynchronous Receiver Transmitter (UART)" + module.description = "Universal Asynchronous Receiver Transmitter (UART)" + def prepare(module, options): device = options[":target"] - if not (device.has_driver("usart:samg*")): + if (not device.has_driver("uart:sam*")) or device.has_driver("sercom:sam"): return False module.depends( @@ -67,17 +73,15 @@ def prepare(module, options): ":platform:gpio", ":platform:clockgen") - global props - drivers = options[":target"].get_all_drivers("usart") + drivers = options[":target"].get_all_drivers("uart") for driver in drivers: for instance in driver["instance"]: module.add_submodule(Instance(driver, instance)) - props["target"] = device.identifier return True + def build(env): - global props - env.substitutions = props + env.substitutions = _get_properties(env) env.outbasepath = "modm/src/modm/platform/uart" - env.copy("uart_base.hpp") + env.template("../uart_base.hpp.in", "uart_base.hpp") diff --git a/src/modm/platform/uart/sam/uart_base.hpp b/src/modm/platform/uart/sam/uart_base.hpp.in similarity index 94% rename from src/modm/platform/uart/sam/uart_base.hpp rename to src/modm/platform/uart/sam/uart_base.hpp.in index 3ec44a304c..a03661d4d5 100644 --- a/src/modm/platform/uart/sam/uart_base.hpp +++ b/src/modm/platform/uart/sam/uart_base.hpp.in @@ -16,7 +16,7 @@ namespace modm::platform { /// @ingroup modm_platform_uart -class UartBase +class {{type}}Base { public: enum class Parity : uint32_t @@ -29,6 +29,7 @@ class UartBase MultiDrop = US_MR_PAR_MULTIDROP }; +%% if type == "usart" enum class WordLength : uint32_t { Bit5 = 0, @@ -37,6 +38,7 @@ class UartBase Bit8, Bit9 }; +%% endif }; } // namespace modm::platform diff --git a/src/modm/platform/uart/sam/usart/module.lb b/src/modm/platform/uart/sam/usart/module.lb new file mode 100644 index 0000000000..bd8e942967 --- /dev/null +++ b/src/modm/platform/uart/sam/usart/module.lb @@ -0,0 +1,88 @@ +#!/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/. +# ----------------------------------------------------------------------------- + +def _get_properties(env, instance=None): + device = env[":target"] + peripheral = "Flexcom" if device.has_driver("flexcom") else "Usart" + return { + "type" : "usart", + "peripheral" : peripheral, + "id" : instance, + "prefix" : "US", + "sr" : "CSR" + } + + +class Instance(Module): + def __init__(self, driver, instance): + self.driver = driver + self.instance = int(instance) + + def init(self, module): + module.name = str(self.instance) + module.description = "Instance {}".format(self.instance) + + def prepare(self, module, options): + module.depends(":platform:usart") + + module.add_option( + NumericOption( + name="buffer.tx", + description="Size of transmit buffer", + minimum=1, maximum=2 ** 16 - 2, + default=64)) + module.add_option( + NumericOption( + name="buffer.rx", + description="Size of receive buffer", + minimum=1, maximum=2 ** 16 - 2, + default=64)) + + return True + + def build(self, env): + env.substitutions = _get_properties(env, self.instance) + env.outbasepath = "modm/src/modm/platform/usart" + + env.template("../uart.hpp.in", "usart_{}.hpp".format(self.instance)) + env.template("../uart.cpp.in", "usart_{}.cpp".format(self.instance)) + + +def init(module): + module.name = ":platform:usart" + module.description = "Universal Synchronous Asynchronous Receiver Transmitter (USART)" + + +def prepare(module, options): + device = options[":target"] + if (not device.has_driver("usart:sam*")) or device.has_driver("sercom:sam"): + return False + + module.depends( + ":architecture:uart", + ":math:algorithm", + ":cmsis:device", + ":platform:gpio", + ":platform:clockgen") + + drivers = options[":target"].get_all_drivers("usart") + for driver in drivers: + for instance in driver["instance"]: + module.add_submodule(Instance(driver, instance)) + + return True + + +def build(env): + env.substitutions = _get_properties(env) + env.outbasepath = "modm/src/modm/platform/usart" + env.template("../uart_base.hpp.in", "usart_base.hpp") diff --git a/tools/scripts/generate_hal_matrix.py b/tools/scripts/generate_hal_matrix.py index 498316d42d..b4ccff0de3 100755 --- a/tools/scripts/generate_hal_matrix.py +++ b/tools/scripts/generate_hal_matrix.py @@ -106,6 +106,7 @@ def hal_get_modules(): "flash": "Internal Flash", "timer": "Timer", "i2c": "I2C", + "usart": "UART" } mname = remap.get(mname, mname.upper()) modules.add(mname) From 264218e652abfb34fa4ffd6790d948c47cc5b588 Mon Sep 17 00:00:00 2001 From: Christopher Durand Date: Wed, 9 Feb 2022 00:01:00 +0100 Subject: [PATCH 06/35] [repo] Enable complete SAMx7x device family --- repo.lb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/repo.lb b/repo.lb index 3e9d94ee66..87fc2b561c 100644 --- a/repo.lb +++ b/repo.lb @@ -86,7 +86,8 @@ class DevicesCache(dict): "stm32h7", "stm32l0", "stm32l1", "stm32l4", "stm32l5", "at90", "attiny", "atmega", - "samd21", "samg55", "samv70", + "samd21", "samg55", + "same70", "sams70", "samv70", "samv71", "samd51", "same51", "same53", "same54", "rp2040", "hosted"] From 50e4c63098db4dfd9f9fc8eb17954500c53dcd89 Mon Sep 17 00:00:00 2001 From: Christopher Durand Date: Thu, 3 Feb 2022 13:18:55 +0100 Subject: [PATCH 07/35] [board] Add SAMV71 Xplained Ultra --- .github/workflows/linux.yml | 2 +- .../board/samv71_xplained_ultra/board.hpp | 111 ++++++++++++++++++ .../board/samv71_xplained_ultra/board.xml | 14 +++ .../board/samv71_xplained_ultra/module.lb | 34 ++++++ .../modm/atmel_samv71_xplained_ultra.cfg | 14 +++ 5 files changed, 174 insertions(+), 1 deletion(-) create mode 100644 src/modm/board/samv71_xplained_ultra/board.hpp create mode 100644 src/modm/board/samv71_xplained_ultra/board.xml create mode 100644 src/modm/board/samv71_xplained_ultra/module.lb create mode 100644 tools/openocd/modm/atmel_samv71_xplained_ultra.cfg diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index c476fff2c3..e8a93c441b 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -100,7 +100,7 @@ jobs: - name: Examples SAMV Devices if: always() run: | - (cd examples && ../tools/scripts/examples_compile.py samv) + (cd examples && ../tools/scripts/examples_compile.py samv samv71_xplained_ultra) - name: Examples RP20 Devices if: always() run: | diff --git a/src/modm/board/samv71_xplained_ultra/board.hpp b/src/modm/board/samv71_xplained_ultra/board.hpp new file mode 100644 index 0000000000..9ae9e57e10 --- /dev/null +++ b/src/modm/board/samv71_xplained_ultra/board.hpp @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2022, Christopher Durand + * + * 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 +#include + +#define MODM_BOARD_HAS_LOGGER + +namespace Board +{ +/// @ingroup modm_board_samv71_xplained_ultra +/// @{ +using namespace modm::literals; +using namespace modm::platform; + +struct SystemClock +{ + // 300MHz system clock generated by PLLA from internal Rc 12MHz clock + static constexpr uint32_t PllAMult = 25; + static constexpr uint32_t Frequency = 300_MHz; + static constexpr uint32_t Mck = Frequency / 2; // 150 MHz max. + static constexpr uint32_t Usart1 = Mck; +// static constexpr uint32_t Usb = 48_MHz; + + static bool inline + enable() + { + ClockGen::setFlashLatency(); // Flash runs off MCK + + ClockGen::enableMainInternal(MainInternalFreq::Rc12Mhz); + ClockGen::selectMainClockSource(MainClockSource::Internal); + ClockGen::enablePllA(); + ClockGen::selectMasterClk(); + ClockGen::updateCoreFrequency(); + + return true; + } +}; + +using Led0 = GpioA23; +using Led1 = GpioC9; +using ButtonSW0 = GpioA9; + +// No SoftwareGpioPort yet for SAM +struct Leds +{ + static constexpr std::size_t width{2}; + + static void setOutput() + { + Led0::setOutput(); + Led1::setOutput(); + } + + static void write(uint32_t value) + { + Led0::set(value & 1); + Led1::set(value & 2); + } +}; + +struct Debug +{ + using Uart = Usart1; + using UartTx = GpioB4; + using UartRx = GpioA21; +}; + +using LoggerDevice = modm::IODeviceWrapper; + +inline void +initialize() +{ + // Turn off the watchdog + WDT->WDT_MR = WDT_MR_WDDIS_Msk; + + SystemClock::enable(); + SysTickTimer::initialize(); + + // Disable JTAG TDI function on debug UART TX pin + MATRIX->CCFG_SYSIO |= CCFG_SYSIO_SYSIO4; + + Debug::Uart::initialize(); + Debug::Uart::connect(); + + Leds::setOutput(); + ButtonSW0::setInput(InputType::PullUp); +} + +/* +// TODO: usb +inline void initializeUsbFs() +{ + //SystemClock::enableUsb(); + //modm::platform::Usb::initialize(); +} +*/ +/// @} + +} // namespace Board + diff --git a/src/modm/board/samv71_xplained_ultra/board.xml b/src/modm/board/samv71_xplained_ultra/board.xml new file mode 100644 index 0000000000..7f75093180 --- /dev/null +++ b/src/modm/board/samv71_xplained_ultra/board.xml @@ -0,0 +1,14 @@ + + + + ../../../../repo.lb + + + + + + + + modm:board:samv71-xplained-ultra + + diff --git a/src/modm/board/samv71_xplained_ultra/module.lb b/src/modm/board/samv71_xplained_ultra/module.lb new file mode 100644 index 0000000000..c2859794fe --- /dev/null +++ b/src/modm/board/samv71_xplained_ultra/module.lb @@ -0,0 +1,34 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# +# Copyright (c) 2021, Jeff McBride +# Copyright (c) 2022, Christopher Durand +# +# 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/. +# ----------------------------------------------------------------------------- + +def init(module): + module.name = ":board:samv71-xplained-ultra" + module.description = "Microchip SAMV71 Xplained Ultra" + +def prepare(module, options): + if not options[":target"].partname == "samv71q21b-aa": + return False + + module.depends(":debug", ":platform:clockgen", ":platform:gpio", ":platform:core", ":platform:usart:1") #, ":platform:usb") + return True + +def build(env): + env.outbasepath = "modm/src/modm/board" + env.substitutions = { + "with_logger": True, + "with_assert": env.has_module(":architecture:assert") + } + env.template("../board.cpp.in", "board.cpp") + env.copy('board.hpp') + env.copy(repopath("tools/openocd/modm/atmel_samv71_xplained_ultra.cfg"), "atmel_samv71_xplained_ultra.cfg") + env.collect(":build:openocd.source", "modm/src/modm/board/atmel_samv71_xplained_ultra.cfg") diff --git a/tools/openocd/modm/atmel_samv71_xplained_ultra.cfg b/tools/openocd/modm/atmel_samv71_xplained_ultra.cfg new file mode 100644 index 0000000000..cb02483dc0 --- /dev/null +++ b/tools/openocd/modm/atmel_samv71_xplained_ultra.cfg @@ -0,0 +1,14 @@ +# +# Atmel SAMV71 Xplained Ultra evaluation kit. +# http://www.atmel.com/tools/ATSAMV71-XULT.aspx +# +# To connect using the EDBG chip on the dev kit over USB, you will +# first need to source [find interface/cmsis-dap.cfg] +# however, since this board also has a SWD+ETM connector, we don't +# automatically source that file here. + +source [find interface/cmsis-dap.cfg] + +set CHIPNAME samv71 + +source [find target/atsamv.cfg] From d4be10aa14cb4421eaba735722c6a56c2825a120 Mon Sep 17 00:00:00 2001 From: Christopher Durand Date: Thu, 3 Feb 2022 13:19:13 +0100 Subject: [PATCH 08/35] [example] Add SAMV71 Xplained Ultra blink example --- examples/samv71_xplained_ultra/blink/main.cpp | 40 +++++++++++++++++++ .../samv71_xplained_ultra/blink/project.xml | 9 +++++ 2 files changed, 49 insertions(+) create mode 100644 examples/samv71_xplained_ultra/blink/main.cpp create mode 100644 examples/samv71_xplained_ultra/blink/project.xml diff --git a/examples/samv71_xplained_ultra/blink/main.cpp b/examples/samv71_xplained_ultra/blink/main.cpp new file mode 100644 index 0000000000..63d68f8de1 --- /dev/null +++ b/examples/samv71_xplained_ultra/blink/main.cpp @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2016-2017, 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/. + */ +// ---------------------------------------------------------------------------- + +#include + +using namespace Board; + +int +main() +{ + Board::initialize(); + + // Use the logging streams to print some messages. + // Change MODM_LOG_LEVEL above to enable or disable these messages + MODM_LOG_DEBUG << "debug" << modm::endl; + MODM_LOG_INFO << "info" << modm::endl; + MODM_LOG_WARNING << "warning" << modm::endl; + MODM_LOG_ERROR << "error" << modm::endl; + + uint32_t counter(0); + + while (true) + { + Led0::toggle(); + Led1::toggle(); + modm::delay(ButtonSW0::read() ? 500ms : 100ms); + + MODM_LOG_INFO << "loop: " << counter++ << modm::endl; + } + + return 0; +} diff --git a/examples/samv71_xplained_ultra/blink/project.xml b/examples/samv71_xplained_ultra/blink/project.xml new file mode 100644 index 0000000000..44ac35294a --- /dev/null +++ b/examples/samv71_xplained_ultra/blink/project.xml @@ -0,0 +1,9 @@ + + modm:samv71-xplained-ultra + + + + + modm:build:scons + + From d31b550527b6bc1ad89591a071694188889b4633 Mon Sep 17 00:00:00 2001 From: Christopher Durand Date: Wed, 9 Feb 2022 02:23:57 +0100 Subject: [PATCH 09/35] [core] Fix SAMx5x and SAMx7x delay --- src/modm/platform/core/sam/module.lb | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/modm/platform/core/sam/module.lb b/src/modm/platform/core/sam/module.lb index ac910d949a..08e871c587 100644 --- a/src/modm/platform/core/sam/module.lb +++ b/src/modm/platform/core/sam/module.lb @@ -35,10 +35,14 @@ def build(env): # delay code that must be tuned for each family # (cycles per loop, setup cost in loops, max cpu frequency) tuning = { - "d": (3, 4, 48), # CM0 tested on D21 in RAM - "g": (6, 4, 120), # G55 - "v": (4, 4, 300), # V70 - }[target.family] + "d2": (3, 4, 48), # CM0 tested on D21 in RAM + "d5": (4, 4, 120), # CM4 tested on E54 in RAM + "e5": (4, 4, 120), # CM4 tested on E54 in RAM + "g5": (6, 4, 120), # G55 + "e7": (4, 4, 300), # CM7 tested on V71 + "s7": (4, 4, 300), # CM7 tested on V71 + "v7": (4, 4, 300), # CM7 tested on V71 + }[target.family + target.series[0]] # us_shift is an optimization to limit error via fractional math us_shift = 32 - math.ceil(math.log2(tuning[2] * 1e6)) From 045fda45286c4ba877b6b55e5ac8a141f1fed239 Mon Sep 17 00:00:00 2001 From: Christopher Durand Date: Wed, 9 Feb 2022 02:25:17 +0100 Subject: [PATCH 10/35] [sam] Fix SAME5x gpio config --- src/modm/platform/gpio/sam/config.hpp.in | 6 +++--- src/modm/platform/gpio/sam/enable.cpp.in | 2 +- src/modm/platform/gpio/sam/module.lb | 1 + src/modm/platform/gpio/sam/pin.hpp.in | 8 ++++---- 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/modm/platform/gpio/sam/config.hpp.in b/src/modm/platform/gpio/sam/config.hpp.in index d8c878f2a1..8aae5587cd 100644 --- a/src/modm/platform/gpio/sam/config.hpp.in +++ b/src/modm/platform/gpio/sam/config.hpp.in @@ -37,7 +37,7 @@ struct Peripherals struct {{ name }} { %% for signal, index_list in peripheral["signals"].items() -%% if not index_list or name == "Adc" +%% if not index_list or (name == "Adc" and not is_d5x_e5x) struct {{ signal }} {}; %% else template @@ -73,7 +73,7 @@ struct Peripherals::{{ name }}<{{ instance }}>::{{ signal }} {}; %% endif %% endfor %% endfor -%% elif name != "Adc" +%% elif name != "Adc" or is_d5x_e5x %% for signal, index_list in peripheral["signals"].items() %% for index in index_list template<> @@ -103,7 +103,7 @@ struct {{ gpio["port"] ~ gpio["pin"] }} %% else using peripheral = Peripherals::{{ signal["peripheral"] }}; %% endif - %% if "index" in signal and signal["peripheral"] != "Adc" + %% if "index" in signal and (signal["peripheral"] != "Adc" or is_d5x_e5x) using signal = peripheral::{{ signal["name"] }}<{{ signal["index"] }}>; %% else using signal = peripheral::{{ signal["name"] }}; diff --git a/src/modm/platform/gpio/sam/enable.cpp.in b/src/modm/platform/gpio/sam/enable.cpp.in index efa607f865..df793bd33f 100644 --- a/src/modm/platform/gpio/sam/enable.cpp.in +++ b/src/modm/platform/gpio/sam/enable.cpp.in @@ -16,7 +16,7 @@ void modm_gpio_enable(void) { -%% if target["family"] in ["g", "v"] +%% if target["family"] in ["g", "v"] or target["series"][0] == "7" PMC->PMC_PCER0 = %% for port in options.enable_ports diff --git a/src/modm/platform/gpio/sam/module.lb b/src/modm/platform/gpio/sam/module.lb index ac5081d7d2..2de92bd709 100644 --- a/src/modm/platform/gpio/sam/module.lb +++ b/src/modm/platform/gpio/sam/module.lb @@ -105,6 +105,7 @@ def build(env): bprops["functions"] = sorted(list(set(s["function"] for gpio in driver["gpio"] for s in gpio["signal"]))) bprops["target"] = device.identifier + bprops["is_d5x_e5x"] = device.identifier.family in ["d", "e"] and device.identifier.series[0] == "5" env.substitutions = bprops env.outbasepath = "modm/src/modm/platform/gpio" diff --git a/src/modm/platform/gpio/sam/pin.hpp.in b/src/modm/platform/gpio/sam/pin.hpp.in index 2d84d7bf29..fdff817ad6 100644 --- a/src/modm/platform/gpio/sam/pin.hpp.in +++ b/src/modm/platform/gpio/sam/pin.hpp.in @@ -109,7 +109,7 @@ struct OneOfSignals static constexpr bool value = ((std::is_same_v) | ...); }; -%% if target["family"] in ["g", "v"] +%% if target["family"] in ["g", "v"] or target["series"][0] == "7" template struct PinMuxMixin @@ -473,7 +473,7 @@ public: inline static bool read() { -%% if target["family"] in ["g", "v"] +%% if target["family"] in ["g", "v"] or target["series"][0] == "7" return Base::template readPortReg(PIO_PDSR_OFFSET); %% else return Base::template readPortReg(PORT_IN_OFFSET); @@ -483,7 +483,7 @@ public: inline static bool isSet() { -%% if target["family"] in ["g", "v"] +%% if target["family"] in ["g", "v"] or target["series"][0] == "7" return Base::template readPortReg(PIO_ODSR_OFFSET); %% else return Base::template readPortReg(PORT_OUT_OFFSET); @@ -547,7 +547,7 @@ struct Gpio::As : public Gpio connect() { -%% if target["family"] in ["g", "v"] +%% if target["family"] in ["g", "v"] or target["series"][0] == "7" // X1 denotes an "extra function", such as an ADC pin, which is not // enabled by the PIO ABCD register. static_assert(PinSignal::function != PinFunction::X1, From 84f5b8e93f86c93bb8d8c4b9f7fa1630b5ae04be Mon Sep 17 00:00:00 2001 From: Christopher Durand Date: Tue, 15 Feb 2022 13:36:46 +0100 Subject: [PATCH 11/35] [sam] Fix ADC gpio data for D/E5x and x7x devices --- src/modm/platform/gpio/sam/config.hpp.in | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/modm/platform/gpio/sam/config.hpp.in b/src/modm/platform/gpio/sam/config.hpp.in index 8aae5587cd..c9ec77f860 100644 --- a/src/modm/platform/gpio/sam/config.hpp.in +++ b/src/modm/platform/gpio/sam/config.hpp.in @@ -37,7 +37,7 @@ struct Peripherals struct {{ name }} { %% for signal, index_list in peripheral["signals"].items() -%% if not index_list or (name == "Adc" and not is_d5x_e5x) +%% if not index_list or (name in ["Adc", "Afec"] and not is_d5x_e5x) struct {{ signal }} {}; %% else template @@ -62,7 +62,7 @@ enum class PortName %% if "instances" in peripheral %% for instance in peripheral["instances"] %% for signal, index_list in peripheral["signals"].items() -%% if index_list +%% if index_list and name != "Afec" %% for index in index_list template<> template<> struct Peripherals::{{ name }}<{{ instance }}>::{{ signal }}<{{ index }}> {}; @@ -73,7 +73,7 @@ struct Peripherals::{{ name }}<{{ instance }}>::{{ signal }} {}; %% endif %% endfor %% endfor -%% elif name != "Adc" or is_d5x_e5x +%% elif name not in ["Adc", "Afec"] or is_d5x_e5x %% for signal, index_list in peripheral["signals"].items() %% for index in index_list template<> @@ -103,12 +103,12 @@ struct {{ gpio["port"] ~ gpio["pin"] }} %% else using peripheral = Peripherals::{{ signal["peripheral"] }}; %% endif - %% if "index" in signal and (signal["peripheral"] != "Adc" or is_d5x_e5x) + %% if "index" in signal and (signal["peripheral"] not in ["Adc", "Afec"] or is_d5x_e5x) using signal = peripheral::{{ signal["name"] }}<{{ signal["index"] }}>; %% else using signal = peripheral::{{ signal["name"] }}; %% endif - %% if signal["peripheral"] == "Adc" and "index" in signal + %% if signal["peripheral"] in ["Adc", "Afec"] and "index" in signal static constexpr int32_t AdcChannel = {{ signal["index"] }}; %% else static constexpr int32_t AdcChannel = -1; From 2941190e9f8991bf9adb61850a96d669ed367c10 Mon Sep 17 00:00:00 2001 From: Christopher Durand Date: Wed, 16 Feb 2022 11:47:25 +0100 Subject: [PATCH 12/35] [sam] Fix macro name collision in ITM driver --- src/modm/platform/uart/cortex/itm.cpp.in | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/modm/platform/uart/cortex/itm.cpp.in b/src/modm/platform/uart/cortex/itm.cpp.in index a089112a9f..1ca1f0f89f 100644 --- a/src/modm/platform/uart/cortex/itm.cpp.in +++ b/src/modm/platform/uart/cortex/itm.cpp.in @@ -134,6 +134,12 @@ Itm::discardTransmitBuffer() %% endif } +%% if target.platform == "sam" +// Some SAM headers define a PORT macro +#pragma push_macro("PORT") +#undef PORT +%% endif + bool Itm::write_itm(uint32_t data, uint8_t size) { @@ -163,6 +169,10 @@ Itm::write_itm(uint32_t data, uint8_t size) return true; } +%% if target.platform == "sam" +#pragma pop_macro("PORT") +%% endif + void Itm::update() { From 527b319b235ad16c0963c4cbd4481f70101f4a7f Mon Sep 17 00:00:00 2001 From: Christopher Durand Date: Fri, 18 Mar 2022 20:34:21 +0100 Subject: [PATCH 13/35] [sam] Add API to enable peripheral APB clocks on devices with GCLK - Parse synchronous APB clock enable information from device headers - Add GCLK API to enable / disable bus clocks This change applies to all SAM devices with GCLK peripheral. --- ext/microchip/module.lb | 37 ++++++++++++++++++++ src/modm/platform/clock/sam/gclk.hpp.in | 19 +++++++++- src/modm/platform/clock/sam/gclk_impl.hpp.in | 26 ++++++++++++++ src/modm/platform/clock/sam/module.lb | 3 +- src/modm/platform/gpio/sam/module.lb | 11 ++++++ 5 files changed, 94 insertions(+), 2 deletions(-) diff --git a/ext/microchip/module.lb b/ext/microchip/module.lb index a875db6af9..8982b40d0d 100644 --- a/ext/microchip/module.lb +++ b/ext/microchip/module.lb @@ -23,9 +23,46 @@ def prepare(module, options): return False module.depends(":cmsis:core") + + module.add_query( + EnvironmentQuery(name="clock-map", factory=clock_map)) + return True pp = {} + +def clock_map_gclk(env, header): + clock_pattern = re.compile(r"^#define\s+(?P(MCLK|PM))_(?P(AHB|APB[A-E]))MASK_(?P([A-Z0-9])+(_2X)?(_[A-Z]+)?)_Pos(\s+)(?P([0-9]+))") + peripheral_pattern = re.compile(r"^(?P[A-Za-z]+([0-9]+[A-Za-z]+)?(_2X)?(_[A-Z]+)?)(?P[0-9]?)$") + clock_map = {} + with open(header, "r") as clock_header: + for line in clock_header: + m = clock_pattern.match(line) + if m: + m2 = peripheral_pattern.match(m.group("per")) + (peripheral, instance) = (m2.group("name"), m2.group("instance")) + if (peripheral, instance) in clock_map: + clock_map[(peripheral, instance)].append((m.group("clk_per"), m.group("clk"), m.group("pos"))) + else: + clock_map[(peripheral, instance)] = [(m.group("clk_per"), m.group("clk"), m.group("pos"))] + return clock_map + +def clock_map(env): + folder = Path(localpath(pp["folder"])) / "component" + clock_file = None + if (folder / "mclk.h").exists(): + clock_file = folder / "mclk.h" + elif (folder / "mclk_100.h").exists(): + clock_file = folder / "mclk_100.h" + elif (folder / "pm.h").exists(): + clock_file = folder / "pm.h" + elif (folder / "pm_100.h").exists(): + clock_file = folder / "pm_100.h" + + if clock_file is not None: + return clock_map_gclk(env, clock_file) + return {} + def validate(env): device = env[":target"] diff --git a/src/modm/platform/clock/sam/gclk.hpp.in b/src/modm/platform/clock/sam/gclk.hpp.in index 8842c53af5..29de0a6f48 100644 --- a/src/modm/platform/clock/sam/gclk.hpp.in +++ b/src/modm/platform/clock/sam/gclk.hpp.in @@ -15,6 +15,7 @@ #include #include "../device.hpp" #include +#include namespace modm::platform { @@ -89,7 +90,7 @@ ClockPeripheral : uint32_t /** * Clock management * - * \ingroup modm_platform_gclk + * @ingroup modm_platform_gclk */ class GenericClockController { @@ -132,6 +133,22 @@ private: %% endif }; +#if defined(__DOXYGEN__) +/// Peripheral AHB/APB bus clock control +/// @ingroup modm_platform_gclk +template +struct PeripheralClock +{ + /// Enable peripheral clock + static void enable(); + /// Disable peripheral clock + static void disable(); +}; +#else +template +struct PeripheralClock; +#endif + } #include "gclk_impl.hpp" diff --git a/src/modm/platform/clock/sam/gclk_impl.hpp.in b/src/modm/platform/clock/sam/gclk_impl.hpp.in index 1f2907a258..f9a09aa05f 100644 --- a/src/modm/platform/clock/sam/gclk_impl.hpp.in +++ b/src/modm/platform/clock/sam/gclk_impl.hpp.in @@ -21,6 +21,32 @@ namespace modm::platform { extern "C" uint32_t SystemCoreClock; +%% for peripheral, clocks in clock_map.items() +template<> +%% set name=peripheral[0] +%% set instance=peripheral[1] +%% if instance +struct PeripheralClock> +%% else +struct PeripheralClock +%% endif +{ + static inline void enable() + { +%% for clock in clocks + {{clock[0]}}->{{clock[1]}}MASK.reg |= (1u << {{clock[2]}}); +%% endfor + } + + static inline void disable() + { +%% for clock in clocks + {{clock[0]}}->{{clock[1]}}MASK.reg &= ~(1u << {{clock[2]}}); +%% endfor + } +}; +%% endfor + template< uint32_t Core_Hz > void GenericClockController::updateCoreFrequency() diff --git a/src/modm/platform/clock/sam/module.lb b/src/modm/platform/clock/sam/module.lb index a6d1c1f206..2dd8e8f683 100644 --- a/src/modm/platform/clock/sam/module.lb +++ b/src/modm/platform/clock/sam/module.lb @@ -41,7 +41,8 @@ def build(env): env.substitutions = { "target": target, "boot_frequency": boot_frequency, - "device_family": device_family + "device_family": device_family, + "clock_map": env.query(":cmsis:device:clock-map") } env.outbasepath = "modm/src/modm/platform/clock" env.template("gclk.hpp.in") diff --git a/src/modm/platform/gpio/sam/module.lb b/src/modm/platform/gpio/sam/module.lb index 2de92bd709..3391ed65a6 100644 --- a/src/modm/platform/gpio/sam/module.lb +++ b/src/modm/platform/gpio/sam/module.lb @@ -4,6 +4,7 @@ # Copyright (c) 2016-2018, Niklas Hauser # Copyright (c) 2017, Fabian Greif # Copyright (c) 2020, Erik Henriksson +# Copyright (c) 2022, Christopher Durand # # This file is part of the modm project. # @@ -101,6 +102,16 @@ def build(env): signals.append(signal) gpio["signal"] = signals + # add peripherals without gpio signals + # the generated types are used in the clock driver api to enable the peripheral clocks + for peripheral_clock in env.query(":cmsis:device:clock-map").keys(): + name, instance = (peripheral_clock[0].capitalize(), peripheral_clock[1]) + if name not in peripherals: + if instance: + peripherals[name] = {"signals" : {}, "instances" : {}} + else: + peripherals[name] = {"signals" : {}} + bprops["peripherals"] = OrderedDict(sorted(peripherals.items())) bprops["functions"] = sorted(list(set(s["function"] for gpio in driver["gpio"] for s in gpio["signal"]))) From 3b93f87dfe1f2a73323abee2601b185682c1d353 Mon Sep 17 00:00:00 2001 From: Christopher Durand Date: Tue, 5 Apr 2022 15:59:52 +0200 Subject: [PATCH 14/35] [sam] Generate GCLK sources and peripheral clocks from device data --- src/modm/platform/clock/sam/gclk.hpp.in | 68 +++++++++---------------- src/modm/platform/clock/sam/module.lb | 6 ++- 2 files changed, 28 insertions(+), 46 deletions(-) diff --git a/src/modm/platform/clock/sam/gclk.hpp.in b/src/modm/platform/clock/sam/gclk.hpp.in index 29de0a6f48..34a25a33ac 100644 --- a/src/modm/platform/clock/sam/gclk.hpp.in +++ b/src/modm/platform/clock/sam/gclk.hpp.in @@ -1,6 +1,7 @@ /* * Copyright (c) 2019, Ethan Slattery * Copyright (c) 2020, Erik Henriksson + * Copyright (c) 2022, Christopher Durand * * This file is part of the modm project. * @@ -12,7 +13,7 @@ #pragma once -#include +#include #include "../device.hpp" #include #include @@ -22,12 +23,12 @@ namespace modm::platform /// @ingroup modm_platform_gclk /// @{ -%% if device_family == "d2x" enum class ClockSource : uint32_t { - OSC8M = GCLK_GENCTRL_SRC_OSC8M_Val, - DFLL48M = GCLK_GENCTRL_SRC_DFLL48M_Val +%% for source in clock_sources + {{ source.name }} = {{ source.value }}{% if not loop.last %},{% endif %} +%% endfor }; enum class @@ -37,52 +38,29 @@ ClockGenerator : uint32_t ExternalCrystal32K = 1, ULP32K = 2, Internal8M = 3, + Main = 0, +%% for i in range(0, generator_count) + Generator{{i}} = {{i}}{% if not loop.last %},{% endif %} +%% endfor }; enum class ClockPeripheral : uint32_t { - Dfll48 = GCLK_CLKCTRL_ID_DFLL48_Val, - Fdpll = GCLK_CLKCTRL_ID_FDPLL_Val, - Fdpll32K = GCLK_CLKCTRL_ID_FDPLL32K_Val, - Wdt = GCLK_CLKCTRL_ID_WDT_Val, - Rtc = GCLK_CLKCTRL_ID_RTC_Val, - Eic = GCLK_CLKCTRL_ID_EIC_Val, - Usb = GCLK_CLKCTRL_ID_USB_Val, - Evsys0 = GCLK_CLKCTRL_ID_EVSYS_0_Val, - Evsys1 = GCLK_CLKCTRL_ID_EVSYS_1_Val, - Evsys2 = GCLK_CLKCTRL_ID_EVSYS_2_Val, - Evsys3 = GCLK_CLKCTRL_ID_EVSYS_3_Val, - Evsys4 = GCLK_CLKCTRL_ID_EVSYS_4_Val, - Evsys5 = GCLK_CLKCTRL_ID_EVSYS_5_Val, - Evsys6 = GCLK_CLKCTRL_ID_EVSYS_6_Val, - Evsys7 = GCLK_CLKCTRL_ID_EVSYS_7_Val, - Evsys8 = GCLK_CLKCTRL_ID_EVSYS_8_Val, - Evsys9 = GCLK_CLKCTRL_ID_EVSYS_9_Val, - Evsys10 = GCLK_CLKCTRL_ID_EVSYS_10_Val, - Evsys11 = GCLK_CLKCTRL_ID_EVSYS_11_Val, - SercomXSlow = GCLK_CLKCTRL_ID_SERCOMX_SLOW_Val, - Sercom0 = GCLK_CLKCTRL_ID_SERCOM0_CORE_Val, - Sercom1 = GCLK_CLKCTRL_ID_SERCOM1_CORE_Val, - Sercom2 = GCLK_CLKCTRL_ID_SERCOM2_CORE_Val, - Sercom3 = GCLK_CLKCTRL_ID_SERCOM3_CORE_Val, - Sercom4 = GCLK_CLKCTRL_ID_SERCOM4_CORE_Val, - Sercom5 = GCLK_CLKCTRL_ID_SERCOM5_CORE_Val, - Tcc0 = GCLK_CLKCTRL_ID_TCC0_TCC1_Val, - Tcc1 = GCLK_CLKCTRL_ID_TCC0_TCC1_Val, - Tcc2 = GCLK_CLKCTRL_ID_TCC2_TC3_Val, - Tc3 = GCLK_CLKCTRL_ID_TCC2_TC3_Val, - Tc4 = GCLK_CLKCTRL_ID_TC4_TC5_Val, - Tc5 = GCLK_CLKCTRL_ID_TC4_TC5_Val, - Tc6 = GCLK_CLKCTRL_ID_TC6_TC7_Val, - Tc7 = GCLK_CLKCTRL_ID_TC6_TC7_Val, - Adc = GCLK_CLKCTRL_ID_ADC_Val, - AcDig = GCLK_CLKCTRL_ID_AC_DIG_Val, - AcAna = GCLK_CLKCTRL_ID_AC_ANA_Val, - Dac = GCLK_CLKCTRL_ID_DAC_Val, - Ptc = GCLK_CLKCTRL_ID_PTC_Val, - I2s0 = GCLK_CLKCTRL_ID_I2S_0_Val, - I2s1 = GCLK_CLKCTRL_ID_I2S_1_Val +%% for clock in peripheral_clocks +%% set instance=clock.get("instance", "") +%% set name=clock.get("name", "") +%% if clock["peripheral"] in ["sysctrl", "oscctrl"] +%% set peripheral="" +%% else +%% set peripheral=clock["peripheral"] +%% endif +%% if clock["peripheral"] == "sercom" and name == "core" +%% set name="" +%% endif +%% set id=peripheral.capitalize() + instance + name.capitalize() + {{ id }} = {{clock["value"]}}{% if not loop.last %},{% endif %} +%% endfor }; /// @} %% endif diff --git a/src/modm/platform/clock/sam/module.lb b/src/modm/platform/clock/sam/module.lb index 2dd8e8f683..76f3d32d04 100644 --- a/src/modm/platform/clock/sam/module.lb +++ b/src/modm/platform/clock/sam/module.lb @@ -25,6 +25,7 @@ def prepare(module, options): def build(env): target = env[":target"].identifier + driver = env[":target"].get_driver("gclk") if target.family in ["d", "e"] and target.series.startswith("5"): device_family = "e5x" @@ -42,7 +43,10 @@ def build(env): "target": target, "boot_frequency": boot_frequency, "device_family": device_family, - "clock_map": env.query(":cmsis:device:clock-map") + "clock_map": env.query(":cmsis:device:clock-map"), + "peripheral_clocks": driver["clock"], + "clock_sources": driver["source"], + "generator_count": int(driver["generators"][0]) } env.outbasepath = "modm/src/modm/platform/clock" env.template("gclk.hpp.in") From c048c907443c5a4412ee8c84f4df8a4bac6c8f35 Mon Sep 17 00:00:00 2001 From: Christopher Durand Date: Tue, 5 Apr 2022 17:59:14 +0200 Subject: [PATCH 15/35] [sam] Implement more complete GCLK driver for D2x/D5x/E5x devices Extended and refactored GCLK driver. All implicit assumption that should be in user code were removed from the driver. Clock generators can be freely configured from user code. Features: - Flexible generator configuration - Clock sources and peripheral sinks from device data - External crystal, external 32k crystal support - Internal oscillator configuration - Dfll48 open/closed loop configuration --- src/modm/platform/clock/sam/gclk.cpp.in | 102 ++---- src/modm/platform/clock/sam/gclk.hpp.in | 158 ++++++++- src/modm/platform/clock/sam/gclk_impl.hpp.in | 335 ++++++++++++++++++- 3 files changed, 501 insertions(+), 94 deletions(-) diff --git a/src/modm/platform/clock/sam/gclk.cpp.in b/src/modm/platform/clock/sam/gclk.cpp.in index a5daf911ee..a8265ade48 100644 --- a/src/modm/platform/clock/sam/gclk.cpp.in +++ b/src/modm/platform/clock/sam/gclk.cpp.in @@ -26,99 +26,51 @@ constinit uint16_t modm_fastdata delay_ns_per_loop(computeDelayNsPerLoop(Generic %% if device_family == "d2x" bool -GenericClockController::initOsc8MHz(uint32_t waitCycles) +GenericClockController::configureOsc8m(Osc8mPrescaler prescaler, uint32_t waitCycles) { - SYSCTRL->OSC8M.bit.PRESC = 0x0; + SYSCTRL->OSC8M.bit.PRESC = static_cast(prescaler); SYSCTRL->OSC8M.bit.ONDEMAND = true; SYSCTRL->OSC8M.bit.RUNSTDBY = false; SYSCTRL->OSC8M.bit.ENABLE = true; while (!SYSCTRL->PCLKSR.bit.OSC8MRDY && --waitCycles); return waitCycles; } +%% endif +%% if device_family == "d2x" +/// Enable DFLL48M in open-loop mode bool -GenericClockController::initExternalCrystal(uint32_t waitCycles) -{ - // Enable external crystal. - SYSCTRL->XOSC32K.reg = - SYSCTRL_XOSC32K_STARTUP( 0x6u ) | - SYSCTRL_XOSC32K_XTALEN | - SYSCTRL_XOSC32K_RUNSTDBY | - SYSCTRL_XOSC32K_EN32K; - // separate call, as described in chapter 15.6.3 - SYSCTRL->XOSC32K.bit.ENABLE = 1; - while (!SYSCTRL->PCLKSR.bit.XOSC32KRDY and --waitCycles) ; - - // Write Generic Clock Generator configuration - GCLK->GENCTRL.reg = - GCLK_GENCTRL_ID(uint32_t(ClockGenerator::ExternalCrystal32K)) | - GCLK_GENCTRL_SRC_XOSC32K | - GCLK_GENCTRL_IDC | - GCLK_GENCTRL_GENEN; - // Wait for synchronization. - while (GCLK->STATUS.bit.SYNCBUSY and --waitCycles) ; - - return waitCycles; -} - -bool -GenericClockController::initDFLL48MHz(uint32_t waitCycles) +GenericClockController::enableDfll48m(uint32_t waitCycles) { - // Put ExternalCrystal as source for the PLL - GCLK->CLKCTRL.reg = - GCLK_CLKCTRL_ID(uint32_t(ClockMux::DFLL48M)) | - GCLK_CLKCTRL_GEN(uint32_t(ClockGenerator::ExternalCrystal32K)) | - GCLK_CLKCTRL_CLKEN; - // Wait for synchronization. - while (GCLK->STATUS.bit.SYNCBUSY and --waitCycles) ; - - // Errata 1.2.1: Disable the OnDemand mode + // Errata 1.2.1: Disable OnDemand mode SYSCTRL->DFLLCTRL.bit.ONDEMAND = 0; - // Wait for synchronization. - while (!SYSCTRL->PCLKSR.bit.DFLLRDY and --waitCycles) ; + // Wait for synchronization + while (!SYSCTRL->PCLKSR.bit.DFLLRDY && waitCycles > 0) --waitCycles; - SYSCTRL->DFLLMUL.reg = - SYSCTRL_DFLLMUL_CSTEP( 31 ) | - SYSCTRL_DFLLMUL_FSTEP( 511 ) | - SYSCTRL_DFLLMUL_MUL(48_MHz / 32'768_Hz); - // Wait for synchronization. - while (!SYSCTRL->PCLKSR.bit.DFLLRDY and --waitCycles) ; + // TODO: is returning the right thing to do? + if (waitCycles == 0) + return false; + + // read calibration data from "NVM Software Calibration Area" (128 bits from address 0x806020) + // DFLL coarse value is in bits 63:58 + const auto calibrationData = *reinterpret_cast(0x806020 + 4); + const auto dfllCoarseCalibration = (calibrationData >> (58 - 32)) & 0b11'1111; + SYSCTRL->DFLLVAL.reg = (dfllCoarseCalibration << SYSCTRL_DFLLVAL_COARSE_Pos) + | (512 << SYSCTRL_DFLLVAL_FINE_Pos); // Write full configuration to DFLL control register - SYSCTRL->DFLLCTRL.reg |= - SYSCTRL_DFLLCTRL_MODE | // Enable the closed loop mode + SYSCTRL->DFLLCTRL.reg = (SYSCTRL->DFLLCTRL.reg | SYSCTRL_DFLLCTRL_WAITLOCK | // No output until DFLL is locked. - SYSCTRL_DFLLCTRL_QLDIS ; // Disable Quick lock - // Wait for synchronization. - while (!SYSCTRL->PCLKSR.bit.DFLLRDY and --waitCycles) ; + SYSCTRL_DFLLCTRL_QLDIS) // Disable quick lock + // Disable closed-loop and USB clock recovery mode + & ~(SYSCTRL_DFLLCTRL_MODE | SYSCTRL_DFLLCTRL_USBCRM); + while (!SYSCTRL->PCLKSR.bit.DFLLRDY); - // Enable the DFLL SYSCTRL->DFLLCTRL.bit.ENABLE = true; - // Wait for locks flags - while ( - not (SYSCTRL->PCLKSR.reg & SYSCTRL_PCLKSR_DFLLLCKC) or - not (SYSCTRL->PCLKSR.reg & SYSCTRL_PCLKSR_DFLLLCKF)); - // Wait for synchronization. - while (!SYSCTRL->PCLKSR.bit.DFLLRDY and --waitCycles) ; + while (!SYSCTRL->PCLKSR.bit.DFLLRDY && waitCycles > 0) --waitCycles; - return waitCycles; -} - -bool -GenericClockController::setSystemClock(ClockSource source, uint32_t waitCycles) -{ - GCLK->GENDIV.reg = - GCLK_GENDIV_ID(uint32_t(ClockGenerator::System)) | - GCLK_GENDIV_DIV(0u); - GCLK->GENCTRL.reg = - GCLK_GENCTRL_ID(uint32_t(ClockGenerator::System)) | - GCLK_GENCTRL_SRC(uint32_t(source)) | - GCLK_GENCTRL_IDC | - GCLK_GENCTRL_GENEN; - // Wait for synchronization. - while (GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY) ; - - return waitCycles; + return waitCycles > 0; } %% endif + } diff --git a/src/modm/platform/clock/sam/gclk.hpp.in b/src/modm/platform/clock/sam/gclk.hpp.in index 34a25a33ac..9c72afc694 100644 --- a/src/modm/platform/clock/sam/gclk.hpp.in +++ b/src/modm/platform/clock/sam/gclk.hpp.in @@ -17,6 +17,7 @@ #include "../device.hpp" #include #include +#include namespace modm::platform { @@ -35,15 +36,31 @@ enum class ClockGenerator : uint32_t { System = 0, - ExternalCrystal32K = 1, - ULP32K = 2, - Internal8M = 3, Main = 0, %% for i in range(0, generator_count) Generator{{i}} = {{i}}{% if not loop.last %},{% endif %} %% endfor }; +struct GeneratorConfiguration +{ + ClockSource source{}; + + /** + * The clock will be divided by the selected divider. + * Normal integer division and division by 2^(N+1) is supported. + * The registers will be automatically configured in the appropriate mode + * for division by powers of 2. + * + * @warning Not all generator instances support the full 16 bit divider value range. + * This is currently not checked yet at compile-time. Only the maximum limits + * are verified. + */ + uint32_t divider = 1; + + bool gpioOutputEnabled = false; +}; + enum class ClockPeripheral : uint32_t { @@ -62,9 +79,69 @@ ClockPeripheral : uint32_t {{ id }} = {{clock["value"]}}{% if not loop.last %},{% endif %} %% endfor }; -/// @} + +%% if device_family == "e5x" +enum class Xosc +{ + Xosc0 = 0, + Xosc1 = 1 +}; +%% endif + +enum class XoscStartupTime +{ + Start_31us = 0x0u, + Start_61us = 0x1u, + Start_122us = 0x2u, + Start_244us = 0x3u, + Start_488us = 0x4u, + Start_977us = 0x5u, + Start_1953us = 0x6u, + Start_3906us = 0x7u, + Start_7813us = 0x8u, + Start_15625us = 0x9u, + Start_31250us = 0xAu, + Start_61250us = 0xBu, + Start_125000us = 0xCu, + Start_250000us = 0xDu, + Start_500000us = 0xEu, + Start_1000000us = 0xFu +}; + +enum class Xosc32StartupTime +{ +%% if device_family == "d2x" + Start_132us = 0x0u, + Start_1ms = 0x1u, + Start_63ms = 0x2u, + Start_125ms = 0x3u, + Start_500ms = 0x4u, + Start_1000ms = 0x5u, + Start_2000ms = 0x6u, + Start_4000ms = 0x7u +%% else + Start_63ms = 0x0u, + Start_125ms = 0x1u, + Start_500ms = 0x2u, + Start_1000ms = 0x3u, + Start_2000ms = 0x4u, + Start_4000ms = 0x5u, + Start_8000ms = 0x6u +%% endif +}; + +%% if device_family == "d2x" + enum class Osc8mPrescaler + { + Prescaler1 = 0x0, + Prescaler2 = 0x1, + Prescaler4 = 0x2, + Prescaler8 = 0x3 + }; %% endif +/// @} + /** * Clock management * @@ -84,31 +161,78 @@ public: updateCoreFrequency(); %% if device_family == "d2x" + /// Configure frequency of the internal oscillator static bool - initOsc8MHz(uint32_t waitCycles = 2048); + configureOsc8m(Osc8mPrescaler prescaler, uint32_t waitCycles = 10'000); + /// Enable DFLL48M in open-loop mode static bool - initExternalCrystal(uint32_t waitCycles = 2048); + enableDfll48m(uint32_t waitCycles = 10'000); +%% endif + /// Enable DFLL48M in closed-loop mode + /// @warning The reference clock on GCLK channel 0 must be available prior to calling this function + template static bool - initDFLL48MHz(uint32_t waitCycles = 2048); + enableDfll48mClosedLoop(uint32_t waitCycles = 10'000); + template static bool - setSystemClock( - ClockSource source = ClockSource::OSC8M, - uint32_t waitCycles = 2048); +%% if device_family == "e5x" + enableExternalCrystal(Xosc clock, uint32_t waitCycles = (1000u << unsigned(startupTime))); +%% else + enableExternalCrystal(uint32_t waitCycles = (1000u << unsigned(startupTime))); +%% endif - template< ClockPeripheral peripheral > + static inline bool +%% if device_family == "e5x" + enableExternalClock(Xosc clock, uint32_t waitCycles = 10'000); +%% else + enableExternalClock(uint32_t waitCycles = 10'000); +%% endif + + static inline bool + enableExternalCrystal32k(Xosc32StartupTime time); + + static inline bool + enableExternalClock32k(); + + template static void connect(ClockGenerator clockGen); + + template + static void + enableGenerator(); + + template + static void + enableGenerator(); + + template + static void + disableGenerator(); + + /** + * Convenience function to configure "Main" clock generator source + * with a divider of 1. + * + * Equivalent to: + * @code + * const auto config = GeneratorConfiguration{ .source = SOURCE, .divider = 1 }; + * GenericClockController::enableGenerator(); + * @endcode + */ + template + static bool + setSystemClock(); + private: + static inline void + sync(); - enum class - ClockMux : uint32_t - { - DFLL48M = 0, - }; -%% endif + static inline void + sync(ClockGenerator clockGen); }; #if defined(__DOXYGEN__) diff --git a/src/modm/platform/clock/sam/gclk_impl.hpp.in b/src/modm/platform/clock/sam/gclk_impl.hpp.in index f9a09aa05f..37781411b5 100644 --- a/src/modm/platform/clock/sam/gclk_impl.hpp.in +++ b/src/modm/platform/clock/sam/gclk_impl.hpp.in @@ -13,9 +13,9 @@ // ---------------------------------------------------------------------------- #include -#include #include #include +#include namespace modm::platform { @@ -90,16 +90,347 @@ GenericClockController::setFlashLatency() return Core_Hz; } +template +bool +GenericClockController::enableDfll48mClosedLoop(uint32_t waitCycles) +{ + static_assert(reference > 732_Hz, "DFLL48 reference frequency must be larger than 732 Hz"); + static_assert(reference < 43_kHz, "DFLL48 reference frequency must be less than 33 kHz"); + constexpr auto multiplier = uint16_t(std::round(48_MHz / double(reference))); + +%% if device_family == "d2x" + // Errata 1.2.1: Disable OnDemand mode + SYSCTRL->DFLLCTRL.bit.ONDEMAND = 0; + // Wait for synchronization + while (!SYSCTRL->PCLKSR.bit.DFLLRDY && waitCycles > 0) --waitCycles; + + // TODO: is returning the right thing to do? + if (waitCycles == 0) + return false; + + // read DFLL coarse value calibration from "NVM Software Calibration Area" (0x806020, 128 bits) + // DFLL coarse calibration value is in bits 63:58 + const auto calibrationData = *reinterpret_cast(0x806020 + 4); + const auto dfllCoarseCalibration = (calibrationData >> (58 - 32)) & 0b11'1111; + SYSCTRL->DFLLVAL.reg = (dfllCoarseCalibration << SYSCTRL_DFLLVAL_COARSE_Pos); + while (!SYSCTRL->PCLKSR.bit.DFLLRDY); + + // Skip coarse lock phase with DFLLVAL.COARSE pre-programmed (17.6.7.1.2 in datasheet) + SYSCTRL->DFLLCTRL.bit.BPLCKC = 1; + while (!SYSCTRL->PCLKSR.bit.DFLLRDY); + + // Set multiplier and adjustment step sizes + // TODO: evaluate step size values + SYSCTRL->DFLLMUL.reg = + SYSCTRL_DFLLMUL_CSTEP(8) | + SYSCTRL_DFLLMUL_FSTEP(8) | + SYSCTRL_DFLLMUL_MUL(multiplier); + while (!SYSCTRL->PCLKSR.bit.DFLLRDY); + + // Write full configuration to DFLL control register + SYSCTRL->DFLLCTRL.reg = (SYSCTRL->DFLLCTRL.reg | + SYSCTRL_DFLLCTRL_MODE | // Enable closed-loop mode + SYSCTRL_DFLLCTRL_WAITLOCK | // No output until DFLL is locked. + SYSCTRL_DFLLCTRL_QLDIS) // Disable quick lock + // Disable USB clock recovery mode + & ~(SYSCTRL_DFLLCTRL_USBCRM); + + SYSCTRL->DFLLCTRL.bit.ENABLE = true; + while (!SYSCTRL->PCLKSR.bit.DFLLRDY && waitCycles > 0) --waitCycles; + // wait for PLL lock + while (!SYSCTRL->PCLKSR.bit.DFLLLCKC && waitCycles > 0) --waitCycles; + while (!SYSCTRL->PCLKSR.bit.DFLLLCKF && waitCycles > 0) --waitCycles; +%% else + // Set multiplier and adjustment step sizes + // TODO: evaluate step size values + OSCCTRL->DFLLMUL.reg = + OSCCTRL_DFLLMUL_CSTEP(8) | + OSCCTRL_DFLLMUL_FSTEP(8) | + OSCCTRL_DFLLMUL_MUL(multiplier); + while (OSCCTRL->DFLLSYNC.bit.DFLLMUL); + + OSCCTRL->DFLLCTRLB.reg = + OSCCTRL_DFLLCTRLB_MODE | // Enable closed-loop mode + OSCCTRL_DFLLCTRLB_QLDIS; // Disable quick lock + while (OSCCTRL->DFLLSYNC.bit.DFLLCTRLB); + + OSCCTRL->DFLLCTRLA.bit.ONDEMAND = 0; + OSCCTRL->DFLLCTRLA.bit.ENABLE = 1; + while (OSCCTRL->DFLLSYNC.bit.ENABLE); + + // wait for PLL lock + while (!OSCCTRL->STATUS.bit.DFLLLCKC && waitCycles > 0) --waitCycles; + while (!OSCCTRL->STATUS.bit.DFLLLCKF && waitCycles > 0) --waitCycles; + while (!OSCCTRL->STATUS.bit.DFLLRDY && waitCycles > 0) --waitCycles; +%% endif + + return waitCycles > 0; +} + %% if device_family == "d2x" template< ClockPeripheral peripheral > void GenericClockController::connect(ClockGenerator clockGen) { + GCLK->CLKCTRL.bit.ID = uint8_t(peripheral); + GCLK->CLKCTRL.bit.CLKEN = 0; + while (GCLK->CLKCTRL.bit.CLKEN); + GCLK->CLKCTRL.reg = GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN(uint32_t(clockGen)) | - GCLK_CLKCTRL_ID(uint32_t(peripheral)); + GCLK_CLKCTRL_ID(uint8_t(peripheral)); + sync(); +} + +void +GenericClockController::sync() +{ + while (GCLK->STATUS.bit.SYNCBUSY); +} + +void +GenericClockController::sync(ClockGenerator) +{ + sync(); +} + +%% elif device_family == "e5x" +void +GenericClockController::sync() +{ + constexpr auto mask = GCLK_SYNCBUSY_GENCTRL_Msk | GCLK_SYNCBUSY_SWRST; + while (GCLK->SYNCBUSY.reg & mask); +} + +void +GenericClockController::sync(ClockGenerator clockGen) +{ + const auto bit = static_cast(clockGen) << GCLK_SYNCBUSY_GENCTRL_Pos; + while (GCLK->SYNCBUSY.reg & bit); +} + +template< ClockPeripheral peripheral > +void +GenericClockController::connect(ClockGenerator clockGen) +{ + auto& reg = GCLK->PCHCTRL[static_cast(peripheral)].reg; + reg = 0; + while (reg != 0); + reg = GCLK_PCHCTRL_CHEN | (static_cast(clockGen) << GCLK_PCHCTRL_GEN_Pos); + sync(clockGen); +} +%% endif + +template +bool +%% if device_family == "e5x" +GenericClockController::enableExternalCrystal(Xosc clock, uint32_t waitCycles) +%% else +GenericClockController::enableExternalCrystal(uint32_t waitCycles) +%% endif +{ +%% if device_family == "e5x" +%% set reg="OSCCTRL->XOSCCTRL[int(clock)]" +%% set prefix="OSCCTRL_XOSCCTRL" +%% set status="OSCCTRL->STATUS.reg & (OSCCTRL_STATUS_XOSCRDY0 << int(clock))" + PeripheralClock::enable(); +%% elif device_family == "d2x" +%% set reg="SYSCTRL->XOSC" +%% set prefix="SYSCTRL_XOSC" +%% set status="SYSCTRL->PCLKSR.bit.XOSCRDY" + PeripheralClock::enable(); +%% endif + {{reg}}.bit.STARTUP = uint32_t(startupTime); + {{reg}}.bit.XTALEN = 1; + // Automatic gain control can only be enabled when the crystal is running +%% if device_family == "e5x" + {{reg}}.bit.ENALC = 0; + if constexpr (frequency <= 8'000'000) { + {{reg}}.bit.IMULT = 0x3; + {{reg}}.bit.IPTAT = 0x2; + } else if constexpr (frequency <= 16'000'000) { + {{reg}}.bit.IMULT = 0x4; + {{reg}}.bit.IPTAT = 0x3; + } else if constexpr (frequency <= 24'000'000) { + {{reg}}.bit.IMULT = 0x5; + {{reg}}.bit.IPTAT = 0x3; + } else { + {{reg}}.bit.IMULT = 0x6; + {{reg}}.bit.IPTAT = 0x3; + } +%% else + {{reg}}.bit.AMPGC = 0; + if constexpr (frequency <= 2'000'000) { + {{reg}}.bit.GAIN = 0x0; + } else if constexpr (frequency <= 4'000'000) { + {{reg}}.bit.GAIN = 0x1; + } else if constexpr (frequency <= 8'000'000) { + {{reg}}.bit.GAIN = 0x2; + } else if constexpr (frequency <= 16'000'000) { + {{reg}}.bit.GAIN = 0x3; + } else { + {{reg}}.bit.GAIN = 0x4; + } +%% endif + + // force oscillator start even if no clock sink is using it yet + {{reg}}.bit.ONDEMAND = 0; + + {{reg}}.bit.ENABLE = 1; + while(!({{status}}) && --waitCycles); + // Enable automatic gain control on success +%% if device_family == "e5x" + {{reg}}.bit.ENALC = waitCycles > 0; +%% else + {{reg}}.bit.AMPGC = waitCycles > 0; +%% endif + return waitCycles; +} + +bool +%% if device_family == "e5x" +GenericClockController::enableExternalClock(Xosc clock, uint32_t waitCycles) +%% else +GenericClockController::enableExternalClock(uint32_t waitCycles) +%% endif +{ +%% if device_family == "e5x" +%% set reg="OSCCTRL->XOSCCTRL[int(clock)]" +%% set status="OSCCTRL->STATUS.reg & (OSCCTRL_STATUS_XOSCRDY0 << int(clock))" + PeripheralClock::enable(); +%% elif device_family == "d2x" +%% set reg="SYSCTRL->XOSC" +%% set status="SYSCTRL->PCLKSR.bit.XOSCRDY" + PeripheralClock::enable(); +%% endif + // force oscillator start even if no clock sink is using it yet + {{reg}}.bit.ONDEMAND = 0; + + {{reg}}.bit.STARTUP = 0; + {{reg}}.bit.XTALEN = 0; + {{reg}}.bit.ENABLE = 1; + while(!({{status}}) && --waitCycles); + return waitCycles; +} + +bool +GenericClockController::enableExternalCrystal32k(Xosc32StartupTime time) +{ +%% if device_family == "d2x" +%% set reg="SYSCTRL->XOSC32K" +%% set status="SYSCTRL->PCLKSR.bit.XOSC32KRDY" + PeripheralClock::enable(); +%% else +%% set reg="OSC32KCTRL->XOSC32K" +%% set status="OSC32KCTRL->STATUS.bit.XOSC32KRDY" + PeripheralClock::enable(); +%% endif + // force oscillator start even if no clock sink is using it yet + {{reg}}.bit.ONDEMAND = 0; +%% if device_family == "d2x" + // disable non-functional automatic gain control, see errata 1.1.1 + {{reg}}.bit.AAMPEN = 0; +%% endif + {{reg}}.bit.EN1K = 1; + {{reg}}.bit.EN32K = 1; + {{reg}}.bit.RUNSTDBY = 1; + {{reg}}.bit.XTALEN = 1; + {{reg}}.bit.STARTUP = static_cast(time); + {{reg}}.bit.ENABLE = 1; + while(!({{status}})); + return true; +} + +bool +GenericClockController::enableExternalClock32k() +{ +%% if device_family == "d2x" +%% set reg="SYSCTRL->XOSC32K" +%% set status="SYSCTRL->PCLKSR.bit.XOSC32KRDY" + PeripheralClock::enable(); +%% else +%% set reg="OSC32KCTRL->XOSC32K" +%% set status="OSC32KCTRL->STATUS.bit.XOSC32KRDY" + PeripheralClock::enable(); +%% endif + // force oscillator start even if no clock sink is using it yet + {{reg}}.bit.ONDEMAND = 0; + + {{reg}}.bit.EN1K = 1; + {{reg}}.bit.EN32K = 1; + {{reg}}.bit.RUNSTDBY = 1; + {{reg}}.bit.XTALEN = 0; + {{reg}}.bit.STARTUP = 0; + {{reg}}.bit.ENABLE = 1; + while(!({{status}})); + return true; } + +template +void +GenericClockController::enableGenerator() +{ + constexpr bool powerOf2 = std::has_single_bit(config.divider) && (config.divider != 1); + constexpr auto dividerReg = powerOf2 ? std::countr_zero(config.divider) : config.divider; + // TODO: check individual divider limits for each generator instance + static_assert(config.divider != 0 && dividerReg <= std::numeric_limits::max(), "Divider out of range"); + +%% if device_family == "d2x" + constexpr auto gen = static_cast(clockGen); + GCLK->GENDIV.reg = + GCLK_GENDIV_ID(gen) | + GCLK_GENDIV_DIV(dividerReg); + GCLK->GENCTRL.reg = + GCLK_GENCTRL_ID(gen) | + GCLK_GENCTRL_SRC(static_cast(config.source)) | + (powerOf2 ? GCLK_GENCTRL_DIVSEL : 0u) | + (config.gpioOutputEnabled ? GCLK_GENCTRL_OE : 0u) | + GCLK_GENCTRL_IDC | + GCLK_GENCTRL_GENEN; +%% else + GCLK->GENCTRL[static_cast(clockGen)].reg = + GCLK_GENCTRL_DIV(dividerReg) | + (powerOf2 ? GCLK_GENCTRL_DIVSEL : 0u) | + (config.gpioOutputEnabled ? GCLK_GENCTRL_OE : 0u) | + GCLK_GENCTRL_IDC | + GCLK_GENCTRL_GENEN | + GCLK_GENCTRL_SRC(static_cast(config.source)); %% endif + sync(clockGen); } +template +void +GenericClockController::enableGenerator() +{ + constexpr auto config = GeneratorConfiguration { + .source = source, + .divider = 1, + .gpioOutputEnabled = false + }; + GenericClockController::enableGenerator(); +} + +template +void +GenericClockController::disableGenerator() +{ +%% if device_family == "d2x" + GCLK->GENCTRL.reg = GCLK_GENCTRL_ID(static_cast(clockGen)); +%% else + GCLK->GENCTRL[static_cast(clockGen)].bit.GENEN = false; +%% endif +} + +template +bool +GenericClockController::setSystemClock() +{ + constexpr auto config = GeneratorConfiguration{ .source = source, .divider = 1 }; + GenericClockController::enableGenerator(); + sync(ClockGenerator::Main); + return true; +} + +} From 52e5a95b07dcb524c7eaef8f142e66d8319f6a39 Mon Sep 17 00:00:00 2001 From: Christopher Durand Date: Tue, 5 Apr 2022 18:23:23 +0200 Subject: [PATCH 16/35] [sam] Add DPLL driver with automatic coefficient calculation --- src/modm/platform/clock/sam/gclk.hpp.in | 109 ++++++++++ src/modm/platform/clock/sam/gclk_impl.hpp.in | 197 +++++++++++++++++++ src/modm/platform/clock/sam/module.lb | 3 +- 3 files changed, 308 insertions(+), 1 deletion(-) diff --git a/src/modm/platform/clock/sam/gclk.hpp.in b/src/modm/platform/clock/sam/gclk.hpp.in index 9c72afc694..7fbc94eace 100644 --- a/src/modm/platform/clock/sam/gclk.hpp.in +++ b/src/modm/platform/clock/sam/gclk.hpp.in @@ -80,6 +80,89 @@ ClockPeripheral : uint32_t %% endfor }; +%% if has_dpll + +struct DpllSource +{ + enum class DpllReference + { + // values correspond to REFCLOCK field in DPLLCTRLB +%% if device_family == "e5x" + Gclk = 0, + Xosc32 = 1, + Xosc0 = 2, + Xosc1 = 3 +%% elif device_family == "d2x" + Xosc32 = 0, + Xosc = 1, + Gclk = 2 +%% endif + }; + + DpllReference reference{}; + frequency_t frequency{}; + + constexpr bool isXoscSource() const + { +%% if device_family == "e5x" + return (reference == DpllReference::Xosc0) + || (reference == DpllReference::Xosc1); +%% elif device_family == "d2x" + return reference == DpllReference::Xosc; +%% endif + } +}; + +template +constexpr DpllSource GclkSource = DpllSource{DpllSource::DpllReference::Gclk, freq}; + +template +constexpr DpllSource Xosc32Source = DpllSource{DpllSource::DpllReference::Xosc32, freq}; + +%% if device_family == "e5x" +template +constexpr DpllSource Xosc0Source = DpllSource{DpllSource::DpllReference::Xosc0, freq}; + +template +constexpr DpllSource Xosc1Source = DpllSource{DpllSource::DpllReference::Xosc1, freq}; +%% elif device_family == "d2x" +template +constexpr DpllSource XoscSource = DpllSource{DpllSource::DpllReference::Xosc, freq}; +%% endif + +struct DpllConfig +{ +%% if device_family == "e5x" + static constexpr uint16_t MultiplierFractionalBits{5}; + static constexpr uint16_t MultiplierIntegerBits{13}; + static constexpr unsigned MaxReference{kHz(3200)}; + static constexpr unsigned MinOutput{MHz(96)}; + static constexpr unsigned MaxOutput{MHz(200)}; +%% elif device_family == "d2x" + static constexpr uint16_t MultiplierFractionalBits{4}; + static constexpr uint16_t MultiplierIntegerBits{12}; + static constexpr unsigned MaxReference{MHz(2)}; + static constexpr unsigned MinOutput{MHz(48)}; + static constexpr unsigned MaxOutput{MHz(96)}; +%% endif + static constexpr unsigned MinReference{kHz(32)}; + // divider operation: f_out = f_in / (2 * (DIV + 1)) + static constexpr uint16_t XoscDividerBits{11}; + + uint16_t integerMultiplier{}; + uint16_t fractionalMultiplier{}; + uint16_t xoscDivider{}; +}; + +%% if device_family == "e5x" +enum class DpllInstance +{ + Dpll0 = 0, + Dpll1 = 1 +}; +%% endif +%% endif + %% if device_family == "e5x" enum class Xosc { @@ -176,6 +259,32 @@ public: static bool enableDfll48mClosedLoop(uint32_t waitCycles = 10'000); + /// Enable PLL with automatically computed coefficients + /// If the specified tolerance is exceeded, compilation will fail. + template + static bool +%% if device_family == "e5x" + enableDpll(DpllInstance instance = DpllInstance::Dpll0); +%% else + enableDpll(); +%% endif + + /// Enable PLL with manual configuration + template + static bool +%% if device_family == "e5x" + enableDpll(DpllInstance instance = DpllInstance::Dpll0); +%% else + enableDpll(); +%% endif + + static inline void +%% if device_family == "e5x" + disableDpll(DpllInstance instance = DpllInstance::Dpll0); +%% else + disableDpll(); +%% endif + template static bool %% if device_family == "e5x" diff --git a/src/modm/platform/clock/sam/gclk_impl.hpp.in b/src/modm/platform/clock/sam/gclk_impl.hpp.in index 37781411b5..0b4c564478 100644 --- a/src/modm/platform/clock/sam/gclk_impl.hpp.in +++ b/src/modm/platform/clock/sam/gclk_impl.hpp.in @@ -15,6 +15,7 @@ #include #include #include +#include #include namespace modm::platform @@ -367,6 +368,202 @@ GenericClockController::enableExternalClock32k() return true; } +%% if has_dpll + +/// @cond +namespace detail +{ + +struct DpllConfigCalculation : DpllConfig +{ + double bestOutputFrequency{}; +}; + +consteval DpllConfigCalculation +findDpllConfig(double inputClock, double target, bool fractional) +{ + uint32_t maxMultiplier = (1u << DpllConfig::MultiplierIntegerBits); + if (fractional) { + maxMultiplier = (1u << (DpllConfig::MultiplierIntegerBits + DpllConfig::MultiplierFractionalBits)); + target *= (1 << DpllConfig::MultiplierFractionalBits); + } + // f_pll = f_reference * (1 + N_int + N_frac/(2^frac_bits)) + const auto idealMultiplier = (target / inputClock) - 1; + const uint32_t multplier = std::min(maxMultiplier, std::round(idealMultiplier)); + if (fractional) { + const auto output = inputClock * (multplier + 1) / (1u << DpllConfig::MultiplierFractionalBits); + return DpllConfigCalculation { + {.integerMultiplier = uint16_t(multplier >> DpllConfig::MultiplierFractionalBits), + .fractionalMultiplier = uint16_t(multplier & ((1u << DpllConfig::MultiplierFractionalBits) - 1)), + .xoscDivider = 0}, + output + }; + } else { + const auto output = inputClock * (multplier + 1); + return DpllConfigCalculation { + {.integerMultiplier = uint16_t(multplier), + .fractionalMultiplier = 0, + .xoscDivider = 0}, + output + }; + } +} + +consteval DpllConfigCalculation +calculateDpllConfigXosc(double xoscClock, double target, bool fractional) +{ + DpllConfigCalculation bestConfig; + bestConfig.bestOutputFrequency = std::numeric_limits::max(); + auto minError = std::numeric_limits::max(); + + for (uint32_t div = 0; div < (1u << DpllConfig::XoscDividerBits); ++div) { + // Xosc divider divides by / (2*(div + 1)) + const double reference = xoscClock / (2*(div + 1)); + if (reference < DpllConfig::MinReference || reference > DpllConfig::MaxReference) continue; + auto result = findDpllConfig(reference, target, fractional); + const auto output = result.bestOutputFrequency; + result.xoscDivider = div; + const double error = std::abs(target - output); + if (error < minError && output >= DpllConfig::MinOutput && output <= DpllConfig::MaxOutput) { + bestConfig = result; + minError = error; + } + } + return bestConfig; +} + +consteval DpllConfigCalculation +findDpllConfigXosc(double xoscClock, double target, uint16_t tolerance_ppm [[maybe_unused]]) +{ + return calculateDpllConfigXosc(xoscClock, target, false); + + // TODO: fractional mode is disabled for now, it was causing an unstable PLL for some parameters + // it can still be used with manually specified coefficients + + // For reducing PLL jitter first try to find a suitable configuration in PLL integer mode. + // In case no solution is found fractional mode is used. + /*DpllConfigCalculation bestConfig{calculateDpllConfigXosc(xoscClock, target, false)}; + const auto output = bestConfig.bestOutputFrequency; + const double error = std::abs(target - output); + + // treat errors below tolerance as exact match + if ((error / target) < (tolerance_ppm * double(1e-6))) { + return bestConfig; + } + + return calculateDpllConfigXosc(xoscClock, target, true);*/ +} + +} +/// @endcond + +template +bool +%% if device_family == "e5x" +GenericClockController::enableDpll(DpllInstance instance) +%% else +GenericClockController::enableDpll() +%% endif +{ + constexpr auto config = [&]() { + if constexpr (source.isXoscSource()) { + return detail::findDpllConfigXosc(source.frequency, output, tolerance_ppm); + } else { + const auto resultInt = detail::findDpllConfig(source.frequency, output, false); + // TODO: fractional mode is disabled for now, because of PLL instability issues + //if (std::abs((resultInt.bestOutputFrequency / output) - 1) < (tolerance_ppm* double(1e-6))) { + return resultInt; + //} + //return detail::findDpllConfig(source.frequency, output, true); + } + }(); + + static_assert(std::abs((config.bestOutputFrequency / output) - 1) <= tolerance_ppm, "DPLL clock tolerance exceeded"); +%% if device_family == "e5x" + return enableDpll(instance); +%% else + return enableDpll(); +%% endif +} + +/// Enable PLL with manual configuration +template +bool +%% if device_family == "e5x" +GenericClockController::enableDpll(DpllInstance instance) +%% else +GenericClockController::enableDpll() +%% endif +{ + constexpr auto reference = source.isXoscSource() ? + double(source.frequency) / (2 * (config.xoscDivider + 1)) : + double(source.frequency); + + static_assert(reference >= DpllConfig::MinReference, "DPLL reference frequency is too low"); + static_assert(reference <= DpllConfig::MaxReference, "DPLL reference frequency is too high"); + + static_assert(config.integerMultiplier < (1 << DpllConfig::MultiplierIntegerBits), + "DPLL integer multplier out of range"); + static_assert(config.fractionalMultiplier < (1 << DpllConfig::MultiplierFractionalBits), + "DPLL fractional multplier out of range"); + + constexpr auto intFactor = config.integerMultiplier; + constexpr auto fracFactor = config.fractionalMultiplier / (1 << DpllConfig::MultiplierFractionalBits); + constexpr auto output = reference * (1 + intFactor + fracFactor); + + static_assert(output >= DpllConfig::MinOutput, "DPLL output frequency is too low"); + static_assert(output <= DpllConfig::MaxOutput, "DPLL output frequency is too high"); + +%% if device_family == "d2x" +%% set dpll_peripheral="SYSCTRL" +%% else +%% set dpll_peripheral="OSCCTRL" +%% endif + +%% if device_family == "e5x" +%% set instance="Dpll[int(instance)]." +%% else +%% set instance="" +%% endif + PeripheralClock::enable(); + {{dpll_peripheral}}->{{instance}}DPLLRATIO.bit.LDR = config.integerMultiplier; + {{dpll_peripheral}}->{{instance}}DPLLRATIO.bit.LDRFRAC = config.fractionalMultiplier; + {{dpll_peripheral}}->{{instance}}DPLLCTRLB.bit.DIV = config.xoscDivider; + {{dpll_peripheral}}->{{instance}}DPLLCTRLB.bit.REFCLK = static_cast(source.reference); +%% if device_family != "d2x" + while({{dpll_peripheral}}->{{instance}}DPLLSYNCBUSY.bit.DPLLRATIO); +%% endif + // force oscillator start even if no clock sink is using it yet + {{dpll_peripheral}}->{{instance}}DPLLCTRLA.bit.ONDEMAND = 0; + + {{dpll_peripheral}}->{{instance}}DPLLCTRLA.bit.ENABLE = 1; +%% if device_family == "d2x" + while(!{{dpll_peripheral}}->{{instance}}DPLLSTATUS.bit.ENABLE); +%% else + while({{dpll_peripheral}}->{{instance}}DPLLSYNCBUSY.bit.ENABLE); +%% endif + uint32_t counter{50000}; + while (counter && !{{dpll_peripheral}}->{{instance}}DPLLSTATUS.bit.CLKRDY) --counter; + while (counter && !{{dpll_peripheral}}->{{instance}}DPLLSTATUS.bit.LOCK) --counter; + return bool(counter); +} + +void +%% if device_family == "e5x" +GenericClockController::disableDpll(DpllInstance instance) +%% else +GenericClockController::disableDpll() +%% endif +{ + {{dpll_peripheral}}->{{instance}}DPLLCTRLA.bit.ENABLE = 0; +%% if device_family == "d2x" + while({{dpll_peripheral}}->{{instance}}DPLLSTATUS.bit.ENABLE); +%% else + while({{dpll_peripheral}}->{{instance}}DPLLSYNCBUSY.bit.ENABLE); +%% endif +} +%% endif + template void GenericClockController::enableGenerator() diff --git a/src/modm/platform/clock/sam/module.lb b/src/modm/platform/clock/sam/module.lb index 76f3d32d04..d7a42b9c44 100644 --- a/src/modm/platform/clock/sam/module.lb +++ b/src/modm/platform/clock/sam/module.lb @@ -46,7 +46,8 @@ def build(env): "clock_map": env.query(":cmsis:device:clock-map"), "peripheral_clocks": driver["clock"], "clock_sources": driver["source"], - "generator_count": int(driver["generators"][0]) + "generator_count": int(driver["generators"][0]), + "has_dpll": device_family in ["d2x", "e5x"] } env.outbasepath = "modm/src/modm/platform/clock" env.template("gclk.hpp.in") From 88eabef859a27c4f9348378a685fcb3dd1480acb Mon Sep 17 00:00:00 2001 From: Christopher Durand Date: Mon, 4 Apr 2022 22:32:31 +0200 Subject: [PATCH 17/35] [sam] Add SAMD5x/E5x USB support --- ext/hathach/module.lb | 5 ++++- ext/hathach/tusb_port.cpp.in | 2 +- src/modm/platform/usb/sam/usb.hpp.in | 7 +++++++ 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/ext/hathach/module.lb b/ext/hathach/module.lb index 085eaf4bf0..534bcb640b 100644 --- a/ext/hathach/module.lb +++ b/ext/hathach/module.lb @@ -105,7 +105,8 @@ def build(env): tusb_config["CFG_TUSB_MCU"] = "OPT_MCU_SAMG" env.copy("tinyusb/src/portable/microchip/samg/", "portable/microchip/samg/") else: - tusb_config["CFG_TUSB_MCU"] = "OPT_MCU_SAM{}{}".format(target.family.upper(), target.series.upper()) + series = "5X" if target.family == "e" and target.series[0] == "5" else target.series.upper() + tusb_config["CFG_TUSB_MCU"] = "OPT_MCU_SAM{}{}".format(target.family.upper(), series) env.copy("tinyusb/src/portable/microchip/samd/", "portable/microchip/samd/") elif target.platform == "rp": @@ -181,6 +182,8 @@ def build(env): irqs = irq_data["port_irqs"][speed] elif target.platform == "sam" and target.family in ["g"]: irqs = ["UDP"] + elif target.platform == "sam" and target.family in ["d", "e"] and target.series[0] == "5": + irqs = ["USB_OTHER", "USB_SOF_HSOF", "USB_TRCPT0", "USB_TRCPT1"] elif target.platform == "rp" and target.family in ["20"]: irqs = ["USBCTRL_IRQ"] else: diff --git a/ext/hathach/tusb_port.cpp.in b/ext/hathach/tusb_port.cpp.in index 37f4554039..29006dfc79 100644 --- a/ext/hathach/tusb_port.cpp.in +++ b/ext/hathach/tusb_port.cpp.in @@ -66,7 +66,7 @@ tusb_get_device_serial(uint16_t *serial_str) ((uint32_t *) UID_BASE), ((uint32_t *) UID_BASE) + 1, ((uint32_t *) UID_BASE) + 2, ((uint32_t *) UID_BASE) + 3 %% elif target.platform in ["sam"] - %% if "samd51" in target.string + %% if "samd51" in target.string or "same5" in target.string (uint32_t *)0x008061FC, (uint32_t *)0x00806010, (uint32_t *)0x00806014, (uint32_t *)0x00806018 %% else diff --git a/src/modm/platform/usb/sam/usb.hpp.in b/src/modm/platform/usb/sam/usb.hpp.in index 1201e1eb46..1d31d90651 100644 --- a/src/modm/platform/usb/sam/usb.hpp.in +++ b/src/modm/platform/usb/sam/usb.hpp.in @@ -46,7 +46,14 @@ public: PM->APBBMASK.reg |= PM_APBBMASK_USB; PM->AHBMASK.reg |= PM_AHBMASK_USB; GenericClockController::connect(ClockGenerator::System); +%% if target["series"][0] == "5" + NVIC_SetPriority(USB_0_IRQn, priority); + NVIC_SetPriority(USB_1_IRQn, priority); + NVIC_SetPriority(USB_2_IRQn, priority); + NVIC_SetPriority(USB_3_IRQn, priority); +%% else NVIC_SetPriority(USB_IRQn, priority); +%% endif %% endif } From 99e9362f4a99d7064b21be6ea32820cbffaba9e6 Mon Sep 17 00:00:00 2001 From: Christopher Durand Date: Fri, 18 Mar 2022 20:37:07 +0100 Subject: [PATCH 18/35] [sam] Adapt peripheral drivers to GCLK changes --- examples/samd/interrupt/main.cpp | 2 +- src/modm/platform/extint/sam/extint.hpp | 4 ++-- src/modm/platform/uart/sam-sercom/uart_hal_impl.hpp.in | 8 +++----- src/modm/platform/usb/sam/usb.hpp.in | 6 ++---- 4 files changed, 8 insertions(+), 12 deletions(-) diff --git a/examples/samd/interrupt/main.cpp b/examples/samd/interrupt/main.cpp index 0e3a9aceb3..c35747a826 100644 --- a/examples/samd/interrupt/main.cpp +++ b/examples/samd/interrupt/main.cpp @@ -27,7 +27,7 @@ int main() { Board::initialize(); - ExternalInterrupt::initialize(); + ExternalInterrupt::initialize(Board::SystemClock::ClockGen32kHz); ExtInt<3>::initialize(&isr); ExtInt<3>::connect(); while (1) diff --git a/src/modm/platform/extint/sam/extint.hpp b/src/modm/platform/extint/sam/extint.hpp index 9f6a365298..01977727de 100644 --- a/src/modm/platform/extint/sam/extint.hpp +++ b/src/modm/platform/extint/sam/extint.hpp @@ -52,10 +52,10 @@ class ExternalInterrupt * @param clockGen * The clock generator to use for the peripheral. If any interrupts are to * 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. + * actually running in standby. */ static void - initialize(ClockGenerator clockGen = ClockGenerator::ExternalCrystal32K, + initialize(ClockGenerator clockGen, int priority = (1ul << __NVIC_PRIO_BITS) - 1ul); protected: diff --git a/src/modm/platform/uart/sam-sercom/uart_hal_impl.hpp.in b/src/modm/platform/uart/sam-sercom/uart_hal_impl.hpp.in index 8cfbddcb59..622b0a7a6d 100644 --- a/src/modm/platform/uart/sam-sercom/uart_hal_impl.hpp.in +++ b/src/modm/platform/uart/sam-sercom/uart_hal_impl.hpp.in @@ -55,9 +55,7 @@ void {{ name }}::initialize(Parity parity) { // Enable peripheral clock in power manager. - PM->APBCMASK.bit.{{ peripheral }}_ = true; - GenericClockController::connect(ClockGenerator::System); - while (GCLK->STATUS.bit.SYNCBUSY); + PeripheralClock>::enable(); // Reset USART reset(); // Set clock mode internal @@ -77,11 +75,11 @@ void {{ peripheral }}->USART.CTRLB.bit.SBMODE = 0x0; // Oversampling 8x or 16x - constexpr uint32_t scalar = (baudrate * 16l > SystemClock::Frequency) ? 8 : 16; + constexpr uint32_t scalar = (baudrate * 16l > SystemClock::{{ sercom | capitalize }}) ? 8 : 16; {{ peripheral }}->USART.CTRLA.bit.SAMPR = (scalar == 16) ? 0x1 : 0x3; // Prescaler 13 bit integer, 3 bit fractional constexpr auto result = Prescaler::from_range( - SystemClock::Frequency/(scalar/8), baudrate, 1, (1ul << 16) - 1ul); + SystemClock::{{ sercom | capitalize }}/(scalar/8), baudrate, 1, (1ul << 16) - 1ul); assertBaudrateInTolerance< result.frequency, baudrate, tolerance >(); {{ peripheral }}->USART.BAUD.FRAC.BAUD = result.prescaler >> 3; {{ peripheral }}->USART.BAUD.FRAC.FP = result.prescaler & 0b111; diff --git a/src/modm/platform/usb/sam/usb.hpp.in b/src/modm/platform/usb/sam/usb.hpp.in index 1d31d90651..3b15040441 100644 --- a/src/modm/platform/usb/sam/usb.hpp.in +++ b/src/modm/platform/usb/sam/usb.hpp.in @@ -42,10 +42,8 @@ public: ClockGen::enable(); NVIC_SetPriority(UDP_IRQn, priority); %% else - static_assert(SystemClock::Frequency == 48_MHz, "Usb must have a 48MHz clock!"); - PM->APBBMASK.reg |= PM_APBBMASK_USB; - PM->AHBMASK.reg |= PM_AHBMASK_USB; - GenericClockController::connect(ClockGenerator::System); + static_assert(SystemClock::Usb == 48_MHz, "Usb must have a 48MHz clock!"); + PeripheralClock::enable(); %% if target["series"][0] == "5" NVIC_SetPriority(USB_0_IRQn, priority); NVIC_SetPriority(USB_1_IRQn, priority); From bdfb83173ec65bffc1339db0d20748cd860692a4 Mon Sep 17 00:00:00 2001 From: Christopher Durand Date: Tue, 19 Oct 2021 18:25:42 +0200 Subject: [PATCH 19/35] [board] Add SAME54 Xplained Pro board --- .github/workflows/linux.yml | 4 + src/modm/board/same54_xplained_pro/board.hpp | 119 ++++++++++++++++++ src/modm/board/same54_xplained_pro/board.xml | 14 +++ src/modm/board/same54_xplained_pro/module.lb | 36 ++++++ .../modm/atmel_same54_xplained_pro.cfg | 12 ++ 5 files changed, 185 insertions(+) create mode 100644 src/modm/board/same54_xplained_pro/board.hpp create mode 100644 src/modm/board/same54_xplained_pro/board.xml create mode 100644 src/modm/board/same54_xplained_pro/module.lb create mode 100644 tools/openocd/modm/atmel_same54_xplained_pro.cfg diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index e8a93c441b..f73c06cd48 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -97,6 +97,10 @@ jobs: if: always() run: | (cd examples && ../tools/scripts/examples_compile.py samg55_xplained_pro) + - name: Examples SAME5x Devices + if: always() + run: | + (cd examples && ../tools/scripts/examples_compile.py same54_xplained_pro) - name: Examples SAMV Devices if: always() run: | diff --git a/src/modm/board/same54_xplained_pro/board.hpp b/src/modm/board/same54_xplained_pro/board.hpp new file mode 100644 index 0000000000..a242acb4e8 --- /dev/null +++ b/src/modm/board/same54_xplained_pro/board.hpp @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2021-2022, Christopher Durand + * 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/. + */ +// ---------------------------------------------------------------------------- +#pragma once + +#include +#include + +#define MODM_BOARD_HAS_LOGGER + +namespace Board +{ +/// @ingroup modm_board_same54_xplained_pro +/// @{ +using namespace modm::literals; +using namespace modm::platform; + + +struct SystemClock +{ + static constexpr uint32_t Frequency = 120_MHz; + + static constexpr uint32_t Clock48MHz = 48_MHz; + static constexpr auto Generator48MHz = ClockGenerator::Generator1; + + static constexpr uint32_t Clock32k = 32768; + static constexpr auto Generator32k = ClockGenerator::Generator2; + + static constexpr uint32_t Usb = Clock48MHz; + + static constexpr uint32_t Sercom2 = Frequency; + static constexpr uint32_t SercomSlow = Clock32k; + + static bool inline + enable() + { + GenericClockController::enableExternalCrystal<12_MHz>(Xosc::Xosc1); + GenericClockController::enableDpll, 120_MHz>(); + + GenericClockController::setFlashLatency(); + GenericClockController::updateCoreFrequency(); + GenericClockController::setSystemClock(); + + GenericClockController::enableExternalCrystal32k(Xosc32StartupTime::Start_500ms); + GenericClockController::enableGenerator(); + + // generate 48 MHz clock from external 32768 Hz crystal reference + GenericClockController::connect(Generator32k); + GenericClockController::enableDfll48mClosedLoop(); + + GenericClockController::enableGenerator(); + GenericClockController::connect(Generator48MHz); + + GenericClockController::connect(ClockGenerator::System); + GenericClockController::connect(Generator32k); + + return true; + } +}; + +using Led0 = GpioC18; +using Button = GpioB31; + +// No SoftwareGpioPort yet for SAM +struct Leds +{ + static constexpr std::size_t width{1}; + + static void setOutput() + { + Led0::setOutput(); + } + + static void write(uint32_t value) + { + Led0::set(value & 1); + } +}; + +struct Debug +{ + using Uart = Uart2; + using UartTx = GpioB25; + using UartRx = GpioB24; +}; + +using LoggerDevice = modm::IODeviceWrapper; + +inline void +initialize() +{ + SystemClock::enable(); + SysTickTimer::initialize(); + + Debug::Uart::initialize(); + Debug::Uart::connect(); + + Led0::setOutput(modm::Gpio::Low); + + Button::setInput(InputType::PullUp); +} + +inline void initializeUsbFs() +{ + modm::platform::Usb::initialize(); + modm::platform::Usb::connect(); +} +/// @} + +} // namespace Board + diff --git a/src/modm/board/same54_xplained_pro/board.xml b/src/modm/board/same54_xplained_pro/board.xml new file mode 100644 index 0000000000..9f074a31ee --- /dev/null +++ b/src/modm/board/same54_xplained_pro/board.xml @@ -0,0 +1,14 @@ + + + + ../../../../repo.lb + + + + + + + + modm:board:same54-xplained-pro + + diff --git a/src/modm/board/same54_xplained_pro/module.lb b/src/modm/board/same54_xplained_pro/module.lb new file mode 100644 index 0000000000..5bb733767c --- /dev/null +++ b/src/modm/board/same54_xplained_pro/module.lb @@ -0,0 +1,36 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# +# Copyright (c) 2021, Jeff McBride +# Copyright (c) 2021-2022, Christopher Durand +# +# 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/. +# ----------------------------------------------------------------------------- + +def init(module): + module.name = ":board:same54-xplained-pro" + module.description = "Microchip SAME54 Xplained Pro" + +def prepare(module, options): + if not options[":target"].partname == "same54p20a-au": + return False + + module.depends(":debug", ":platform:gclk", ":platform:gpio", ":platform:core", ":platform:usb", ":platform:uart:2") + return True + +def build(env): + env.outbasepath = "modm/src/modm/board" + env.substitutions = { + "with_logger": True, + "with_assert": env.has_module(":architecture:assert") + } + env.template("../board.cpp.in", "board.cpp") + env.copy('board.hpp') + + env.outbasepath = "modm/openocd/modm/board/" + env.copy(repopath("tools/openocd/modm/atmel_same54_xplained_pro.cfg"), "atmel_same54_xplained_pro.cfg") + env.collect(":build:openocd.source", "modm/board/atmel_same54_xplained_pro.cfg") diff --git a/tools/openocd/modm/atmel_same54_xplained_pro.cfg b/tools/openocd/modm/atmel_same54_xplained_pro.cfg new file mode 100644 index 0000000000..3b3adccc7f --- /dev/null +++ b/tools/openocd/modm/atmel_same54_xplained_pro.cfg @@ -0,0 +1,12 @@ +# +# Atmel SAME54 Xplained Pro evaluation kit. +# https://www.microchip.com/en-us/development-tool/ATSAME54-XPRO +# + +source [find interface/cmsis-dap.cfg] + +# chip name +set CHIPNAME ATSAME54P20 + +source [find target/atsame5x.cfg] + From 22a5d3199b3c4d66a7044679189ebda260a3130c Mon Sep 17 00:00:00 2001 From: Christopher Durand Date: Tue, 19 Oct 2021 19:36:38 +0200 Subject: [PATCH 20/35] [example] Add SAME54 Xplained Pro blink example --- examples/same54_xplained_pro/blink/main.cpp | 39 +++++++++++++++++++ .../same54_xplained_pro/blink/project.xml | 10 +++++ 2 files changed, 49 insertions(+) create mode 100644 examples/same54_xplained_pro/blink/main.cpp create mode 100644 examples/same54_xplained_pro/blink/project.xml diff --git a/examples/same54_xplained_pro/blink/main.cpp b/examples/same54_xplained_pro/blink/main.cpp new file mode 100644 index 0000000000..90716c8993 --- /dev/null +++ b/examples/same54_xplained_pro/blink/main.cpp @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2016-2017, 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/. + */ +// ---------------------------------------------------------------------------- + +#include + +using namespace Board; + +int +main() +{ + Board::initialize(); + + // Use the logging streams to print some messages. + // Change MODM_LOG_LEVEL above to enable or disable these messages + MODM_LOG_DEBUG << "debug" << modm::endl; + MODM_LOG_INFO << "info" << modm::endl; + MODM_LOG_WARNING << "warning" << modm::endl; + MODM_LOG_ERROR << "error" << modm::endl; + + uint32_t counter(0); + + while (true) + { + Led0::toggle(); + modm::delay(Button::read() ? 500ms : 100ms); + + MODM_LOG_INFO << "loop: " << counter++ << modm::endl; + } + + return 0; +} diff --git a/examples/same54_xplained_pro/blink/project.xml b/examples/same54_xplained_pro/blink/project.xml new file mode 100644 index 0000000000..fa74596a8f --- /dev/null +++ b/examples/same54_xplained_pro/blink/project.xml @@ -0,0 +1,10 @@ + + modm:same54-xplained-pro + + + + + modm:build:scons + modm:platform:uart:1 + + From 3ec9f1ef1150718559c662a2fe548addcf6a1024 Mon Sep 17 00:00:00 2001 From: Christopher Durand Date: Mon, 4 Apr 2022 22:42:04 +0200 Subject: [PATCH 21/35] [sam] Fix systick frequency on SAMD5x/E5x --- src/modm/platform/clock/systick/module.lb | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/modm/platform/clock/systick/module.lb b/src/modm/platform/clock/systick/module.lb index cb0681e145..9793e21ee9 100644 --- a/src/modm/platform/clock/systick/module.lb +++ b/src/modm/platform/clock/systick/module.lb @@ -40,8 +40,13 @@ def build(env): # SysTick clock prescaler is dynamically chosen as /1 or /8 div = 8 - # SAMD: Prescaler not implemented - if target.platform == "sam" and target.family in ["d"]: + # SAMD5x/E5x: Prescaler not implemented + if target.platform == "sam" and target.family in ["d", "e"] and target.series[0] == "5": + div = 1 + # systick clock is too fast to run at 4 Hz, increase frequency + freq = 8 + # SAMD2x: Prescaler not implemented + elif target.platform == "sam" and target.family in ["d"]: div = 1 # H742/43: Prescaler not implemented in revY elif target.family == "h7" and target.name in ["42", "43", "50", "53"] and target.revision == "y": From bbf3cc1360d7ccff0ca43b102ac58c95caf5a525 Mon Sep 17 00:00:00 2001 From: Christopher Durand Date: Tue, 5 Apr 2022 14:43:01 +0200 Subject: [PATCH 22/35] [board] Adapt SAMD21 boards to GCLK changes --- src/modm/board/feather_m0/board.hpp | 54 ++++++++++++++-------------- src/modm/board/samd21_mini/board.hpp | 48 +++++++++++-------------- 2 files changed, 46 insertions(+), 56 deletions(-) diff --git a/src/modm/board/feather_m0/board.hpp b/src/modm/board/feather_m0/board.hpp index 2b18fd3551..19860e77eb 100644 --- a/src/modm/board/feather_m0/board.hpp +++ b/src/modm/board/feather_m0/board.hpp @@ -2,6 +2,7 @@ * Copyright (c) 2016-2017, Sascha Schade * Copyright (c) 2017-2018, Niklas Hauser * Copyright (c) 2020, Erik Henriksson + * Copyright (c) 2022, Christopher Durand * * This file is part of the modm project. * @@ -60,42 +61,39 @@ using RadioCs = GpioA06; // This is the red LED by the USB jack. using Led = D13; -/// samd21g18a running at 48MHz generated from the external 32.768 KHz crystal +/// samd21g18a running at 48MHz generated from the external 32.768 kHz crystal struct SystemClock { - static constexpr uint32_t Frequency = 48_MHz; - static constexpr uint32_t Usb = 48_MHz; - // static constexpr uint32_t Ahb = Frequency; - // static constexpr uint32_t Apba = Frequency; - // static constexpr uint32_t Apbb = Frequency; - // static constexpr uint32_t Apbc = Frequency; - - // static constexpr uint32_t Adc = Apb2; - - // static constexpr uint32_t SercomSlow = Apb2; - // static constexpr uint32_t Sercom0 = Apb2; - // static constexpr uint32_t Sercom1 = Apb2; - // static constexpr uint32_t Sercom2 = Apb2; - // static constexpr uint32_t Sercom3 = Apb2; - // static constexpr uint32_t Sercom4 = Apb2; - // static constexpr uint32_t Sercom5 = Apb2; - - // static constexpr uint32_t Apb1Timer = Apb1 * 2; - // static constexpr uint32_t Apb2Timer = Apb2 * 1; - // static constexpr uint32_t Timer1 = Apb2Timer; - // static constexpr uint32_t Timer2 = Apb1Timer; - // static constexpr uint32_t Timer3 = Apb1Timer; - // static constexpr uint32_t Timer4 = Apb1Timer; + static constexpr uint32_t Dfll48m = 48_MHz; + static constexpr uint32_t Xosc32k = 32768_Hz; + + static constexpr uint32_t Frequency = Dfll48m; + static constexpr uint32_t Usb = Dfll48m; + + static constexpr uint32_t Sercom0 = Frequency; + static constexpr uint32_t SercomSlow = Xosc32k; + + static constexpr auto ClockGen32kHz = ClockGenerator::Generator2; static bool inline enable() { + // Configure GCLK generator 2 with external 32k crystal source + GenericClockController::enableExternalCrystal32k(Xosc32StartupTime::Start_500ms); + GenericClockController::enableGenerator(); + + // generate 48 MHz from 32768 Hz crystal reference + GenericClockController::connect(ClockGen32kHz); + GenericClockController::enableDfll48mClosedLoop(); + GenericClockController::setFlashLatency(); - GenericClockController::initExternalCrystal(); - GenericClockController::initDFLL48MHz(); - GenericClockController::initOsc8MHz(); - GenericClockController::setSystemClock(ClockSource::DFLL48M); + GenericClockController::setSystemClock(); GenericClockController::updateCoreFrequency(); + + GenericClockController::connect(ClockGenerator::System); + GenericClockController::connect(ClockGen32kHz); + + GenericClockController::connect(ClockGenerator::System); return true; } }; diff --git a/src/modm/board/samd21_mini/board.hpp b/src/modm/board/samd21_mini/board.hpp index 89e81f8fce..d54c53cd3b 100644 --- a/src/modm/board/samd21_mini/board.hpp +++ b/src/modm/board/samd21_mini/board.hpp @@ -1,6 +1,7 @@ /* * Copyright (c) 2016-2017, Sascha Schade * Copyright (c) 2017-2018, Niklas Hauser + * Copyright (c) 2022, Christopher Durand * * This file is part of the modm project. * @@ -25,39 +26,30 @@ using namespace modm::literals; struct SystemClock { - static constexpr uint32_t Frequency = 48_MHz; - // static constexpr uint32_t Ahb = Frequency; - // static constexpr uint32_t Apba = Frequency; - // static constexpr uint32_t Apbb = Frequency; - // static constexpr uint32_t Apbc = Frequency; - - static constexpr uint32_t Usb = 48_MHz; - // static constexpr uint32_t Adc = Apb2; - - // static constexpr uint32_t SercomSlow = Apb2; - // static constexpr uint32_t Sercom0 = Apb2; - // static constexpr uint32_t Sercom1 = Apb2; - // static constexpr uint32_t Sercom2 = Apb2; - // static constexpr uint32_t Sercom3 = Apb2; - // static constexpr uint32_t Sercom4 = Apb2; - // static constexpr uint32_t Sercom5 = Apb2; - - // static constexpr uint32_t Apb1Timer = Apb1 * 2; - // static constexpr uint32_t Apb2Timer = Apb2 * 1; - // static constexpr uint32_t Timer1 = Apb2Timer; - // static constexpr uint32_t Timer2 = Apb1Timer; - // static constexpr uint32_t Timer3 = Apb1Timer; - // static constexpr uint32_t Timer4 = Apb1Timer; + static constexpr uint32_t Dfll48m = 48_MHz; + static constexpr uint32_t Xosc32k = 32768_Hz; + + static constexpr uint32_t Frequency = Dfll48m; + static constexpr uint32_t Usb = Dfll48m; + + static constexpr auto ClockGen32kHz = ClockGenerator::Generator2; static bool inline enable() { + // Configure GCLK generator 2 with external 32k crystal source + GenericClockController::enableExternalCrystal32k(Xosc32StartupTime::Start_500ms); + GenericClockController::enableGenerator(); + + // generate 48 MHz from 32768 Hz crystal reference + GenericClockController::connect(ClockGen32kHz); + GenericClockController::enableDfll48mClosedLoop(); + GenericClockController::setFlashLatency(); - GenericClockController::initExternalCrystal(); - GenericClockController::initDFLL48MHz(); - GenericClockController::initOsc8MHz(); - GenericClockController::setSystemClock(ClockSource::DFLL48M); + GenericClockController::setSystemClock(); GenericClockController::updateCoreFrequency(); + + GenericClockController::connect(ClockGenerator::System); return true; } }; @@ -103,7 +95,7 @@ initialize() } inline void -initializeUsbFs(uint8_t priority=3) +initializeUsbFs(uint8_t priority = 3) { Usb::initialize(priority); Usb::connect(); From facfe48a25b01167f993120ce9e7647e20e473f6 Mon Sep 17 00:00:00 2001 From: Christopher Durand Date: Mon, 4 Apr 2022 22:49:54 +0200 Subject: [PATCH 23/35] [example] Add SAME54 Xplained PRO USB example --- .../same54_xplained_pro/usbserial/main.cpp | 44 +++++++++++++++++++ .../same54_xplained_pro/usbserial/project.xml | 12 +++++ 2 files changed, 56 insertions(+) create mode 100644 examples/same54_xplained_pro/usbserial/main.cpp create mode 100644 examples/same54_xplained_pro/usbserial/project.xml diff --git a/examples/same54_xplained_pro/usbserial/main.cpp b/examples/same54_xplained_pro/usbserial/main.cpp new file mode 100644 index 0000000000..2bf24ef589 --- /dev/null +++ b/examples/same54_xplained_pro/usbserial/main.cpp @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2016-2017, Niklas Hauser + * Copyright (c) 2022, Christopher Durand + * + * 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 +#include + +using namespace Board; + +modm::IODeviceWrapper usb_io_device; +modm::IOStream usb_stream(usb_io_device); + +int +main() +{ + Board::initialize(); + Board::initializeUsbFs(); + + tusb_init(); + + usb_stream << "Hello from USB" << modm::endl; + + uint32_t counter(0); + + modm::PeriodicTimer timer{500ms}; + while (true) + { + tud_task(); + if (timer.execute()) { + Led0::toggle(); + usb_stream << "loop: " << counter++ << modm::endl; + } + } + + return 0; +} diff --git a/examples/same54_xplained_pro/usbserial/project.xml b/examples/same54_xplained_pro/usbserial/project.xml new file mode 100644 index 0000000000..a43ae490d0 --- /dev/null +++ b/examples/same54_xplained_pro/usbserial/project.xml @@ -0,0 +1,12 @@ + + modm:same54-xplained-pro + + + + + + modm:tinyusb + modm:build:scons + modm:processing:timer + + From d8f369eab4217cb26c7424e4eccd604ee371f3c1 Mon Sep 17 00:00:00 2001 From: Christopher Durand Date: Mon, 4 Apr 2022 23:39:10 +0200 Subject: [PATCH 24/35] [sam] Enable PMC clock driver for all devices with PMC --- src/modm/platform/clock/sam_pmc/clockgen.cpp.in | 4 ++-- src/modm/platform/clock/sam_pmc/clockgen.hpp.in | 14 +++++++++----- .../platform/clock/sam_pmc/clockgen_impl.hpp.in | 12 ++++++------ src/modm/platform/clock/sam_pmc/module.lb | 3 +-- src/modm/platform/gpio/sam/module.lb | 2 ++ 5 files changed, 20 insertions(+), 15 deletions(-) diff --git a/src/modm/platform/clock/sam_pmc/clockgen.cpp.in b/src/modm/platform/clock/sam_pmc/clockgen.cpp.in index 38b272c5c7..10da4cd2f3 100644 --- a/src/modm/platform/clock/sam_pmc/clockgen.cpp.in +++ b/src/modm/platform/clock/sam_pmc/clockgen.cpp.in @@ -73,7 +73,7 @@ ClockGen::masterClkFrequency() %% if target.family in ["g"] case MasterClkSource::PLLB_CLK: return pllBFrequency() / div; -%% elif target.family in ["v"] +%% elif target.series[0] == "7" case MasterClkSource::UPLL_CLK: return 240'000'000; // UPLLDIV2 %% endif @@ -115,7 +115,7 @@ ClockGen::pllAFrequency() %% if target.family in ["g"] uint32_t freq = SlowClkFreqHz * mul; if(PMC->PMC_MCKR & PMC_MCKR_PLLADIV2) freq /= 2; -%% elif target.family in ["v"] +%% elif target.series[0] == "7" uint32_t freq = mainClkFrequency() * mul; const auto diva = ((PMC->CKGR_PLLAR & CKGR_PLLAR_DIVA_Msk) >> CKGR_PLLAR_DIVA_Pos); if (diva == 0) return 0; // PLLA is disabled diff --git a/src/modm/platform/clock/sam_pmc/clockgen.hpp.in b/src/modm/platform/clock/sam_pmc/clockgen.hpp.in index 37479970c5..4cba706312 100644 --- a/src/modm/platform/clock/sam_pmc/clockgen.hpp.in +++ b/src/modm/platform/clock/sam_pmc/clockgen.hpp.in @@ -38,7 +38,7 @@ MasterClkSource : uint32_t PLLA_CLK = PMC_MCKR_CSS_PLLA_CLK_Val, %% if target.family in ["g"] PLLB_CLK = PMC_MCKR_CSS_PLLB_CLK_Val, -%% elif target.family in ["v"] +%% elif target.series[0] == "7" UPLL_CLK = PMC_MCKR_CSS_UPLL_CLK_Val, %% endif }; @@ -60,7 +60,7 @@ enum class MasterClkDivider : uint8_t { Div1 = 0, -%% if target.family in ["v"] +%% if target.series[0] == "7" Div2 = PMC_MCKR_MDIV_PCK_DIV2_Val, Div4 = PMC_MCKR_MDIV_PCK_DIV4_Val, Div3 = PMC_MCKR_MDIV_PCK_DIV3_Val, @@ -139,7 +139,7 @@ ClockPeripheral : uint32_t Flexcom5 = ID_FLEXCOM5, Flexcom6 = ID_FLEXCOM6, Flexcom7 = ID_FLEXCOM7, -%% elif target.family in ["v"] +%% elif target.series[0] == "7" Xdmac = ID_XDMAC, #ifdef ID_UART0 Uart0 = ID_UART0, @@ -199,20 +199,24 @@ ClockPeripheral : uint32_t Ssc = ID_SSC, Afec0 = ID_AFEC0, Afec1 = ID_AFEC1, +#ifdef ID_DACC Dacc = ID_DACC, +#endif Pwm0 = ID_PWM0, Pwm1 = ID_PWM1, Icm = ID_ICM, Acc = ID_ACC, Usb = ID_USBHS, +#ifdef ID_MLB Mlb = ID_MLB, +#endif Aes = ID_AES, Trng = ID_TRNG, Isi = ID_ISI, %% endif }; -%% if target.family in ["v"] +%% if target.series[0] == "7" enum class UtmiRefClk : uint32_t { @@ -279,7 +283,7 @@ public: enablePllB(uint32_t wait_cycles = 50); %% endif -%% if target.family in ["v"] +%% if target.series[0] == "7" template static void enableUPll(uint32_t wait_cycles = 50); diff --git a/src/modm/platform/clock/sam_pmc/clockgen_impl.hpp.in b/src/modm/platform/clock/sam_pmc/clockgen_impl.hpp.in index 97f84d5cfa..32b49a1430 100644 --- a/src/modm/platform/clock/sam_pmc/clockgen_impl.hpp.in +++ b/src/modm/platform/clock/sam_pmc/clockgen_impl.hpp.in @@ -53,7 +53,7 @@ ClockGen::selectMasterClk() static_assert(divider == MasterClkDivider::Div1, "Divider for master clock is not supported"); constexpr bool isPll = (src == MasterClkSource::PLLA_CLK || src == MasterClkSource::PLLB_CLK); -%% elif target.family in ["v"] +%% elif target.series[0] == "7" constexpr bool isPll = (src == MasterClkSource::PLLA_CLK || src == MasterClkSource::UPLL_CLK); %% endif @@ -61,7 +61,7 @@ ClockGen::selectMasterClk() if constexpr (isPll) { PMC->PMC_MCKR = (PMC->PMC_MCKR & ~PMC_MCKR_PRES_Msk) | PMC_MCKR_PRES((uint32_t)pres); while(!(PMC->PMC_SR & PMC_SR_MCKRDY)) {} -%% if target.family in ["v"] +%% if target.series[0] == "7" PMC->PMC_MCKR = (PMC->PMC_MCKR & ~PMC_MCKR_MDIV_Msk) | PMC_MCKR_MDIV(uint32_t(divider)); while(!(PMC->PMC_SR & PMC_SR_MCKRDY)) {} %% endif @@ -72,7 +72,7 @@ ClockGen::selectMasterClk() while(!(PMC->PMC_SR & PMC_SR_MCKRDY)) {} PMC->PMC_MCKR = (PMC->PMC_MCKR & ~PMC_MCKR_PRES_Msk) | PMC_MCKR_PRES((uint32_t)pres); while(!(PMC->PMC_SR & PMC_SR_MCKRDY)) {} -%% if target.family in ["v"] +%% if target.series[0] == "7" PMC->PMC_MCKR = (PMC->PMC_MCKR & ~PMC_MCKR_MDIV_Msk) | PMC_MCKR_MDIV(uint32_t(divider)); while(!(PMC->PMC_SR & PMC_SR_MCKRDY)) {} %% endif @@ -86,7 +86,7 @@ ClockGen::enablePllA(uint32_t wait_cycles) %% if target.family in ["g"] static_assert(9 <= multiplier && multiplier <= 7501, "Valid PLL MUL range is 9-7501"); static_assert(divider == 1, "PLL divider not supported"); -%% elif target.family in ["v"] +%% elif target.series[0] == "7" static_assert(1 <= multiplier && multiplier <= 62, "Valid PLL MUL range is 1-62"); static_assert(1 <= divider && divider <= 255, "Valid PLL DIV range is 1-255"); %% endif @@ -96,7 +96,7 @@ ClockGen::enablePllA(uint32_t wait_cycles) CKGR_PLLAR_PLLACOUNT(wait_cycles) | %% if target.family in ["g"] CKGR_PLLAR_PLLAEN(1); -%% elif target.family in ["v"] +%% elif target.series[0] == "7" CKGR_PLLAR_ONE | CKGR_PLLAR_DIVA(divider); %% endif @@ -119,7 +119,7 @@ ClockGen::enablePllB(uint32_t wait_cycles) } %% endif -%% if target.family in ["v"] +%% if target.series[0] == "7" template void ClockGen::enableUPll(uint32_t wait_cycles) diff --git a/src/modm/platform/clock/sam_pmc/module.lb b/src/modm/platform/clock/sam_pmc/module.lb index 5ea13eabac..1ebc680e78 100644 --- a/src/modm/platform/clock/sam_pmc/module.lb +++ b/src/modm/platform/clock/sam_pmc/module.lb @@ -15,8 +15,7 @@ def init(module): module.description = "Clock Generator (CKGR)" def prepare(module, options): - if not (options[":target"].has_driver("pmc:samg*") - or options[":target"].has_driver("pmc:samv*")): + if not options[":target"].has_driver("pmc:sam*"): return False module.depends(":cmsis:device", ":platform:clock") diff --git a/src/modm/platform/gpio/sam/module.lb b/src/modm/platform/gpio/sam/module.lb index 3391ed65a6..ab1824b687 100644 --- a/src/modm/platform/gpio/sam/module.lb +++ b/src/modm/platform/gpio/sam/module.lb @@ -100,6 +100,8 @@ def build(env): signal["index"] = int(signal["index"]) p_signal.add(signal["index"]) signals.append(signal) + # remove duplicated dicts from list of dicts + signals = [dict(t) for t in {tuple(d.items()) for d in signals}] gpio["signal"] = signals # add peripherals without gpio signals From a705b677f87b75a59c6dcb92620bbf197fd8354f Mon Sep 17 00:00:00 2001 From: Christopher Durand Date: Tue, 5 Apr 2022 01:03:41 +0200 Subject: [PATCH 25/35] [sam] Fix inconsistent macros for SAME70 "B"-variant --- src/modm/platform/uart/sam/uart.cpp.in | 15 ++++-- src/modm/platform/uart/sam/uart.hpp.in | 17 ++++--- src/modm/platform/uart/sam/uart/module.lb | 3 +- src/modm/platform/uart/sam/uart_base.hpp.in | 55 ++++++++++++++------- src/modm/platform/uart/sam/usart/module.lb | 3 +- 5 files changed, 62 insertions(+), 31 deletions(-) diff --git a/src/modm/platform/uart/sam/uart.cpp.in b/src/modm/platform/uart/sam/uart.cpp.in index cc5a4898f0..3fc610118e 100644 --- a/src/modm/platform/uart/sam/uart.cpp.in +++ b/src/modm/platform/uart/sam/uart.cpp.in @@ -16,6 +16,11 @@ %% set name="{}{}".format(type.capitalize(), id) %% set reg=name.upper() +%% if type == "usart" and target.family == "e" and target.variant == "b" +%% set reg_suffix="_USART" +%% else +%% set reg_suffix="" +%% endif namespace { @@ -34,7 +39,7 @@ MODM_ISR({{ peripheral | upper }}{{ id }}) if({{ name }}::isTransmitReady()) { if(txBuffer.isEmpty()) { - {{ name }}::Regs()->{{ prefix }}_IDR = {{ prefix }}_IDR_TXRDY; + {{ name }}::Regs()->{{ prefix }}_IDR = {{ prefix }}_IDR_TXRDY_Msk; } else { {{ name }}::Regs()->{{ prefix }}_THR = txBuffer.get(); txBuffer.pop(); @@ -80,7 +85,7 @@ bool return false; } // Enable tx interrupt - Regs()->{{ prefix }}_IER = {{ prefix }}_IER_TXRDY; + Regs()->{{ prefix }}_IER = {{ prefix }}_IER_TXRDY_Msk; } return true; } @@ -112,7 +117,7 @@ void void {{ name }}::setParity(Parity parity) { - Regs()->{{ prefix }}_MR = (Regs()->{{ prefix }}_MR & ~{{ prefix }}_MR_PAR_Msk) | (uint32_t)parity; + Regs()->{{ prefix }}_MR = (Regs()->{{ prefix }}_MR & ~{{ prefix }}_MR{{reg_suffix}}_PAR_Msk) | (uint32_t)parity; } %% if type == "usart" @@ -120,9 +125,9 @@ void {{ name }}::setWordLength(WordLength length) { if(length == WordLength::Bit9) { - Regs()->{{ prefix }}_MR |= {{ prefix }}_MR_MODE9; + Regs()->{{ prefix }}_MR |= {{ prefix }}_MR{{reg_suffix}}_MODE9_Msk; } else { - Regs()->{{ prefix }}_MR &= ~{{ prefix }}_MR_MODE9; + Regs()->{{ prefix }}_MR &= ~{{ prefix }}_MR{{reg_suffix}}_MODE9_Msk; Regs()->{{ prefix }}_MR = (Regs()->{{ prefix }}_MR & ~{{ prefix }}_MR_CHRL_Msk) | {{ prefix }}_MR_CHRL((uint32_t)length); diff --git a/src/modm/platform/uart/sam/uart.hpp.in b/src/modm/platform/uart/sam/uart.hpp.in index 0ad8f4ea4f..5cff5f6351 100644 --- a/src/modm/platform/uart/sam/uart.hpp.in +++ b/src/modm/platform/uart/sam/uart.hpp.in @@ -20,6 +20,11 @@ %% set name="{}{}".format(type.capitalize(), id) %% set reg=name.upper() +%% if type == "usart" and target.family == "e" and target.variant == "b" +%% set reg_suffix="_USART" +%% else +%% set reg_suffix="" +%% endif namespace modm::platform { @@ -35,7 +40,7 @@ namespace modm::platform * @author Christopher Durand * @ingroup modm_platform_{{type}} modm_platform_{{type}}_{{id}} */ -class {{ name }} : public {{ type }}Base, public modm::Uart +class {{ name }} : public {{ type | capitalize }}Base, public modm::Uart { private: // prevent name collision between ::Uart* from SAM header with modm::Uart @@ -104,16 +109,16 @@ public: %% if type == "usart" // Use 8x oversampling (this affects baud rate generation) - Regs()->{{ prefix }}_MR = {{ prefix }}_MR_OVER; + Regs()->{{ prefix }}_MR = {{ prefix }}_MR{{reg_suffix}}_OVER; %% endif setParity(parity); %% if type == "usart" setWordLength(length); %% endif - Regs()->{{ prefix }}_CR = {{ prefix }}_CR_RXEN | {{ prefix }}_CR_TXEN; + Regs()->{{ prefix }}_CR = {{ prefix }}_CR_RXEN_Msk | {{ prefix }}_CR_TXEN_Msk; // Enable rx interrupt - Regs()->{{ prefix }}_IER = {{ prefix }}_IER_RXRDY; + Regs()->{{ prefix }}_IER = {{ prefix }}_IER_RXRDY_Msk; // Enable the IRQ NVIC_SetPriority({{ peripheral | upper }}{{ id }}_IRQn, irq_priority); @@ -138,9 +143,9 @@ public: static void setWordLength(WordLength length); %% endif - static inline bool isTransmitReady() { return Regs()->{{ prefix }}_{{ sr }} & {{ prefix }}_{{ sr }}_TXRDY; } + static inline bool isTransmitReady() { return Regs()->{{ prefix }}_{{ sr }} & {{ prefix }}_{{ sr }}_TXRDY_Msk; } - static inline bool isReceiveReady() { return Regs()->{{ prefix }}_{{ sr }} & {{ prefix }}_{{ sr }}_RXRDY; } + static inline bool isReceiveReady() { return Regs()->{{ prefix }}_{{ sr }} & {{ prefix }}_{{ sr }}_RXRDY_Msk; } }; } // namespace modm::platform diff --git a/src/modm/platform/uart/sam/uart/module.lb b/src/modm/platform/uart/sam/uart/module.lb index c66b837bdd..6443f5f231 100644 --- a/src/modm/platform/uart/sam/uart/module.lb +++ b/src/modm/platform/uart/sam/uart/module.lb @@ -17,7 +17,8 @@ def _get_properties(env, instance=None): "peripheral" : "Uart", "id" : instance, "prefix" : "UART", - "sr" : "SR" + "sr" : "SR", + "target" : device.identifier } diff --git a/src/modm/platform/uart/sam/uart_base.hpp.in b/src/modm/platform/uart/sam/uart_base.hpp.in index a03661d4d5..cde1297e70 100644 --- a/src/modm/platform/uart/sam/uart_base.hpp.in +++ b/src/modm/platform/uart/sam/uart_base.hpp.in @@ -1,5 +1,6 @@ /* * Copyright (c) 2021, Jeff McBride + * Copyright (c) 2022, Christopher Durand * * This file is part of the modm project. * @@ -8,6 +9,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // ---------------------------------------------------------------------------- + #pragma once #include "../device.hpp" @@ -16,28 +18,45 @@ namespace modm::platform { /// @ingroup modm_platform_uart -class {{type}}Base +class {{type | capitalize}}Base { public: - enum class Parity : uint32_t - { - Disabled = US_MR_PAR_NO, - Even = US_MR_PAR_EVEN, - Odd = US_MR_PAR_ODD, - Space = US_MR_PAR_SPACE, - Mark = US_MR_PAR_MARK, - MultiDrop = US_MR_PAR_MULTIDROP - }; + enum class Parity : uint32_t + { +%% if type == "usart" +%% if target.family == "e" and target.variant == "b" + Disabled = US_MR_USART_PAR_NO_Val, + Even = US_MR_USART_PAR_EVEN_Val, + Odd = US_MR_USART_PAR_ODD_Val, + Space = US_MR_USART_PAR_SPACE_Val, + Mark = US_MR_USART_PAR_MARK_Val, + MultiDrop = US_MR_USART_PAR_MULTIDROP_Val +%% else + Disabled = US_MR_PAR_NO, + Even = US_MR_PAR_EVEN, + Odd = US_MR_PAR_ODD, + Space = US_MR_PAR_SPACE, + Mark = US_MR_PAR_MARK, + MultiDrop = US_MR_PAR_MULTIDROP +%% endif +%% else + Disabled = UART_MR_PAR_NO, + Even = UART_MR_PAR_EVEN, + Odd = UART_MR_PAR_ODD, + Space = UART_MR_PAR_SPACE, + Mark = UART_MR_PAR_MARK +%% endif + }; %% if type == "usart" - enum class WordLength : uint32_t - { - Bit5 = 0, - Bit6, - Bit7, - Bit8, - Bit9 - }; + enum class WordLength : uint32_t + { + Bit5 = 0, + Bit6, + Bit7, + Bit8, + Bit9 + }; %% endif }; diff --git a/src/modm/platform/uart/sam/usart/module.lb b/src/modm/platform/uart/sam/usart/module.lb index bd8e942967..d9768d5861 100644 --- a/src/modm/platform/uart/sam/usart/module.lb +++ b/src/modm/platform/uart/sam/usart/module.lb @@ -18,7 +18,8 @@ def _get_properties(env, instance=None): "peripheral" : peripheral, "id" : instance, "prefix" : "US", - "sr" : "CSR" + "sr" : "CSR", + "target" : device.identifier } From e22ab457366a623580bc1a9ac77276b560f48a90 Mon Sep 17 00:00:00 2001 From: Christopher Durand Date: Tue, 5 Apr 2022 23:12:58 +0200 Subject: [PATCH 26/35] [board] Fix compilation of samd-mini bsp when using USB --- src/modm/board/samd21_mini/board.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modm/board/samd21_mini/board.hpp b/src/modm/board/samd21_mini/board.hpp index d54c53cd3b..5ef27846eb 100644 --- a/src/modm/board/samd21_mini/board.hpp +++ b/src/modm/board/samd21_mini/board.hpp @@ -97,8 +97,8 @@ initialize() inline void initializeUsbFs(uint8_t priority = 3) { - Usb::initialize(priority); - Usb::connect(); + modm::platform::Usb::initialize(priority); + modm::platform::Usb::connect(); } /// @} From fcbd455236f08c9342bffefeb48f2bb175be6c5f Mon Sep 17 00:00:00 2001 From: Christopher Durand Date: Mon, 22 Aug 2022 18:23:33 +0200 Subject: [PATCH 27/35] [sam] Adapt to new family naming scheme --- README.md | 54 +++++++++++++------ ext/hathach/module.lb | 10 ++-- ext/microchip/module.lb | 4 +- .../board/samv71_xplained_ultra/board.xml | 2 +- .../board/samv71_xplained_ultra/module.lb | 2 +- src/modm/platform/clock/sam/gclk.cpp.in | 4 +- src/modm/platform/clock/sam/gclk.hpp.in | 36 ++++++------- src/modm/platform/clock/sam/gclk_impl.hpp.in | 52 +++++++++--------- src/modm/platform/clock/sam/module.lb | 26 +++++---- .../platform/clock/sam_pmc/clockgen.cpp.in | 10 ++-- .../platform/clock/sam_pmc/clockgen.hpp.in | 18 +++---- .../clock/sam_pmc/clockgen_impl.hpp.in | 20 +++---- src/modm/platform/clock/systick/module.lb | 4 +- src/modm/platform/core/sam/module.lb | 13 ++--- .../platform/core/sam/startup_platform.c.in | 13 +---- src/modm/platform/gpio/sam/config.hpp.in | 6 +-- src/modm/platform/gpio/sam/enable.cpp.in | 3 +- src/modm/platform/gpio/sam/module.lb | 1 - src/modm/platform/gpio/sam/pin.hpp.in | 8 +-- src/modm/platform/uart/sam/uart.cpp.in | 2 +- src/modm/platform/uart/sam/uart.hpp.in | 2 +- src/modm/platform/uart/sam/uart_base.hpp.in | 2 +- src/modm/platform/usb/sam/usb.hpp.in | 6 +-- tools/scripts/generate_hal_matrix.py | 6 ++- tools/scripts/generate_module_docs.py | 2 +- 25 files changed, 161 insertions(+), 145 deletions(-) diff --git a/README.md b/README.md index f1189a1773..b80d0cf4fb 100644 --- a/README.md +++ b/README.md @@ -80,10 +80,10 @@ git clone --recurse-submodules --jobs 8 https://github.com/modm-io/modm.git ## Microcontrollers -modm can create a HAL for 3304 devices of these vendors: +modm can create a HAL for 3534 devices of these vendors: - STMicroelectronics STM32: 2729 devices. -- Microchip SAM: 186 devices. +- Microchip SAM: 416 devices. - Microchip AVR: 388 devices. - Raspberry Pi: 1 device. @@ -103,7 +103,7 @@ Please [discover modm's peripheral drivers for your specific device][discover]. STM32 -SAM +SAM RP AT @@ -121,9 +121,10 @@ Please [discover modm's peripheral drivers for your specific device][discover]. L1 L4 L5 -D21 -G55 -V70 +D1x
D2x
DAx +D5x
E5x +E7x
S7x
V7x +G5x 20 90 Mega @@ -144,8 +145,9 @@ Please [discover modm's peripheral drivers for your specific device][discover]. ✅ ✅ ○ -✅ ○ +○ +✅ ✅ ○ ✅ @@ -166,9 +168,10 @@ Please [discover modm's peripheral drivers for your specific device][discover]. ✅ ✅ ✕ -✕ +○ ○ ✕ +✕ ○ ○ ✕ @@ -188,9 +191,10 @@ Please [discover modm's peripheral drivers for your specific device][discover]. ✅ ○ ○ -✕ +○ ○ ✕ +✕ ○ ○ ○ @@ -210,8 +214,9 @@ Please [discover modm's peripheral drivers for your specific device][discover]. ✅ ✅ ○ -✕ ○ +○ +✕ ✕ ✕ ○ @@ -232,8 +237,9 @@ Please [discover modm's peripheral drivers for your specific device][discover]. ✅ ✅ ○ -✕ ○ +○ +✕ ✅ ✕ ✕ @@ -254,7 +260,8 @@ Please [discover modm's peripheral drivers for your specific device][discover]. ✕ ✕ ✕ -✕ +○ +○ ✕ ✕ ✕ @@ -278,6 +285,7 @@ Please [discover modm's peripheral drivers for your specific device][discover]. ✅ ○ ○ +○ ✅ ✅ ✅ @@ -300,6 +308,7 @@ Please [discover modm's peripheral drivers for your specific device][discover]. ✕ ✕ ○ +✕ ○ ✕ ✕ @@ -326,6 +335,7 @@ Please [discover modm's peripheral drivers for your specific device][discover]. ✅ ✅ ✅ +✅ I2C ✅ @@ -344,6 +354,7 @@ Please [discover modm's peripheral drivers for your specific device][discover]. ○ ○ ○ +○ ✅ ✅ ✅ @@ -366,6 +377,7 @@ Please [discover modm's peripheral drivers for your specific device][discover]. ○ ○ ○ +○ ✕ ✕ ✕ @@ -386,12 +398,13 @@ Please [discover modm's peripheral drivers for your specific device][discover]. ✅ ✅ ✕ -✕ +○ ○ ✕ ✕ ✕ ✕ +✕ SPI ✅ @@ -408,12 +421,13 @@ Please [discover modm's peripheral drivers for your specific device][discover]. ✅ ✅ ○ -✅ +○ ○ ✅ ✅ ✅ ✅ +✅ System Clock ✅ @@ -433,6 +447,7 @@ Please [discover modm's peripheral drivers for your specific device][discover]. ✅ ✅ ✅ +✅ ✕ ✕ ✕ @@ -452,9 +467,10 @@ Please [discover modm's peripheral drivers for your specific device][discover]. ✅ ✅ ○ -✅ ○ ○ +✅ +○ ○ ○ ○ @@ -479,6 +495,7 @@ Please [discover modm's peripheral drivers for your specific device][discover]. ✅ ✅ ✅ +✅ ○ Unique ID @@ -502,6 +519,7 @@ Please [discover modm's peripheral drivers for your specific device][discover]. ✕ ✕ ✕ +✕ USB ✅ @@ -521,6 +539,7 @@ Please [discover modm's peripheral drivers for your specific device][discover]. ✅ ○ ✅ +✅ ✕ ✕ ✕ @@ -613,12 +632,15 @@ We have out-of-box support for many development boards including documentation. Raspberry Pi Pico SAMD21-MINI +SAME54-XPLAINED-PRO SAMG55-XPLAINED-PRO +SAMV71-XPLAINED-ULTRA + Smart Response XE STM32-F4VE - STM32F030-DEMO THINGPLUS-RP2040 + diff --git a/ext/hathach/module.lb b/ext/hathach/module.lb index 534bcb640b..f0273488c2 100644 --- a/ext/hathach/module.lb +++ b/ext/hathach/module.lb @@ -101,12 +101,12 @@ def build(env): env.copy("tinyusb/src/portable/st/synopsys", "portable/st/synopsys/") elif target.platform == "sam": - if target.family == "g": + if target.family == "g5x": tusb_config["CFG_TUSB_MCU"] = "OPT_MCU_SAMG" env.copy("tinyusb/src/portable/microchip/samg/", "portable/microchip/samg/") else: - series = "5X" if target.family == "e" and target.series[0] == "5" else target.series.upper() - tusb_config["CFG_TUSB_MCU"] = "OPT_MCU_SAM{}{}".format(target.family.upper(), series) + series = "e5x" if target.series.startswith("e5") else target.series + tusb_config["CFG_TUSB_MCU"] = "OPT_MCU_SAM{}".format(series.upper()) env.copy("tinyusb/src/portable/microchip/samd/", "portable/microchip/samd/") elif target.platform == "rp": @@ -180,9 +180,9 @@ def build(env): if target.platform == "stm32": irq_data = env.query(":platform:usb:irqs") irqs = irq_data["port_irqs"][speed] - elif target.platform == "sam" and target.family in ["g"]: + elif target.platform == "sam" and target.family in ["g5x"]: irqs = ["UDP"] - elif target.platform == "sam" and target.family in ["d", "e"] and target.series[0] == "5": + elif target.platform == "sam" and target.family in ["d5x/e5x"]: irqs = ["USB_OTHER", "USB_SOF_HSOF", "USB_TRCPT0", "USB_TRCPT1"] elif target.platform == "rp" and target.family in ["20"]: irqs = ["USBCTRL_IRQ"] diff --git a/ext/microchip/module.lb b/ext/microchip/module.lb index 8982b40d0d..24f88b87a1 100644 --- a/ext/microchip/module.lb +++ b/ext/microchip/module.lb @@ -68,8 +68,8 @@ def validate(env): # Some families use the variant in header defines, some do not (e.g. SAMG) names = [ - "".join([device.identifier[f] for f in ["platform", "family", "series", "pin", "flash", "variant"]]), - "".join([device.identifier[f] for f in ["platform", "family", "series", "pin", "flash"]]), + "".join([device.identifier[f] for f in ["platform", "series", "pin", "flash", "variant"]]), + "".join([device.identifier[f] for f in ["platform", "series", "pin", "flash"]]), ] device_define = None diff --git a/src/modm/board/samv71_xplained_ultra/board.xml b/src/modm/board/samv71_xplained_ultra/board.xml index 7f75093180..b13402668a 100644 --- a/src/modm/board/samv71_xplained_ultra/board.xml +++ b/src/modm/board/samv71_xplained_ultra/board.xml @@ -6,7 +6,7 @@ - + modm:board:samv71-xplained-ultra diff --git a/src/modm/board/samv71_xplained_ultra/module.lb b/src/modm/board/samv71_xplained_ultra/module.lb index c2859794fe..1b08b54603 100644 --- a/src/modm/board/samv71_xplained_ultra/module.lb +++ b/src/modm/board/samv71_xplained_ultra/module.lb @@ -16,7 +16,7 @@ def init(module): module.description = "Microchip SAMV71 Xplained Ultra" def prepare(module, options): - if not options[":target"].partname == "samv71q21b-aa": + if not options[":target"].partname == "samv71q21b-aab": return False module.depends(":debug", ":platform:clockgen", ":platform:gpio", ":platform:core", ":platform:usart:1") #, ":platform:usb") diff --git a/src/modm/platform/clock/sam/gclk.cpp.in b/src/modm/platform/clock/sam/gclk.cpp.in index a8265ade48..0b7e1759f0 100644 --- a/src/modm/platform/clock/sam/gclk.cpp.in +++ b/src/modm/platform/clock/sam/gclk.cpp.in @@ -24,7 +24,7 @@ namespace modm::platform constinit uint16_t modm_fastdata delay_fcpu_MHz(computeDelayMhz(GenericClockController::BootFrequency)); constinit uint16_t modm_fastdata delay_ns_per_loop(computeDelayNsPerLoop(GenericClockController::BootFrequency)); -%% if device_family == "d2x" +%% if target.family == "d1x/d2x/dax" bool GenericClockController::configureOsc8m(Osc8mPrescaler prescaler, uint32_t waitCycles) { @@ -37,7 +37,7 @@ GenericClockController::configureOsc8m(Osc8mPrescaler prescaler, uint32_t waitCy } %% endif -%% if device_family == "d2x" +%% if target.family == "d1x/d2x/dax" /// Enable DFLL48M in open-loop mode bool GenericClockController::enableDfll48m(uint32_t waitCycles) diff --git a/src/modm/platform/clock/sam/gclk.hpp.in b/src/modm/platform/clock/sam/gclk.hpp.in index 7fbc94eace..397b0acc0e 100644 --- a/src/modm/platform/clock/sam/gclk.hpp.in +++ b/src/modm/platform/clock/sam/gclk.hpp.in @@ -87,12 +87,12 @@ struct DpllSource enum class DpllReference { // values correspond to REFCLOCK field in DPLLCTRLB -%% if device_family == "e5x" +%% if target.family == "d5x/e5x" Gclk = 0, Xosc32 = 1, Xosc0 = 2, Xosc1 = 3 -%% elif device_family == "d2x" +%% elif target.family == "d1x/d2x/dax" Xosc32 = 0, Xosc = 1, Gclk = 2 @@ -104,10 +104,10 @@ struct DpllSource constexpr bool isXoscSource() const { -%% if device_family == "e5x" +%% if target.family == "d5x/e5x" return (reference == DpllReference::Xosc0) || (reference == DpllReference::Xosc1); -%% elif device_family == "d2x" +%% elif target.family == "d1x/d2x/dax" return reference == DpllReference::Xosc; %% endif } @@ -119,26 +119,26 @@ constexpr DpllSource GclkSource = DpllSource{DpllSource::DpllReference::Gclk, fr template constexpr DpllSource Xosc32Source = DpllSource{DpllSource::DpllReference::Xosc32, freq}; -%% if device_family == "e5x" +%% if target.family == "d5x/e5x" template constexpr DpllSource Xosc0Source = DpllSource{DpllSource::DpllReference::Xosc0, freq}; template constexpr DpllSource Xosc1Source = DpllSource{DpllSource::DpllReference::Xosc1, freq}; -%% elif device_family == "d2x" +%% elif target.family == "d1x/d2x/dax" template constexpr DpllSource XoscSource = DpllSource{DpllSource::DpllReference::Xosc, freq}; %% endif struct DpllConfig { -%% if device_family == "e5x" +%% if target.family == "d5x/e5x" static constexpr uint16_t MultiplierFractionalBits{5}; static constexpr uint16_t MultiplierIntegerBits{13}; static constexpr unsigned MaxReference{kHz(3200)}; static constexpr unsigned MinOutput{MHz(96)}; static constexpr unsigned MaxOutput{MHz(200)}; -%% elif device_family == "d2x" +%% elif target.family == "d1x/d2x/dax" static constexpr uint16_t MultiplierFractionalBits{4}; static constexpr uint16_t MultiplierIntegerBits{12}; static constexpr unsigned MaxReference{MHz(2)}; @@ -154,7 +154,7 @@ struct DpllConfig uint16_t xoscDivider{}; }; -%% if device_family == "e5x" +%% if target.family == "d5x/e5x" enum class DpllInstance { Dpll0 = 0, @@ -163,7 +163,7 @@ enum class DpllInstance %% endif %% endif -%% if device_family == "e5x" +%% if target.family == "d5x/e5x" enum class Xosc { Xosc0 = 0, @@ -193,7 +193,7 @@ enum class XoscStartupTime enum class Xosc32StartupTime { -%% if device_family == "d2x" +%% if target.family == "d1x/d2x/dax" Start_132us = 0x0u, Start_1ms = 0x1u, Start_63ms = 0x2u, @@ -213,7 +213,7 @@ enum class Xosc32StartupTime %% endif }; -%% if device_family == "d2x" +%% if target.family == "d1x/d2x/dax" enum class Osc8mPrescaler { Prescaler1 = 0x0, @@ -243,7 +243,7 @@ public: static void updateCoreFrequency(); -%% if device_family == "d2x" +%% if target.family == "d1x/d2x/dax" /// Configure frequency of the internal oscillator static bool configureOsc8m(Osc8mPrescaler prescaler, uint32_t waitCycles = 10'000); @@ -263,7 +263,7 @@ public: /// If the specified tolerance is exceeded, compilation will fail. template static bool -%% if device_family == "e5x" +%% if target.family == "d5x/e5x" enableDpll(DpllInstance instance = DpllInstance::Dpll0); %% else enableDpll(); @@ -272,14 +272,14 @@ public: /// Enable PLL with manual configuration template static bool -%% if device_family == "e5x" +%% if target.family == "d5x/e5x" enableDpll(DpllInstance instance = DpllInstance::Dpll0); %% else enableDpll(); %% endif static inline void -%% if device_family == "e5x" +%% if target.family == "d5x/e5x" disableDpll(DpllInstance instance = DpllInstance::Dpll0); %% else disableDpll(); @@ -287,14 +287,14 @@ public: template static bool -%% if device_family == "e5x" +%% if target.family == "d5x/e5x" enableExternalCrystal(Xosc clock, uint32_t waitCycles = (1000u << unsigned(startupTime))); %% else enableExternalCrystal(uint32_t waitCycles = (1000u << unsigned(startupTime))); %% endif static inline bool -%% if device_family == "e5x" +%% if target.family == "d5x/e5x" enableExternalClock(Xosc clock, uint32_t waitCycles = 10'000); %% else enableExternalClock(uint32_t waitCycles = 10'000); diff --git a/src/modm/platform/clock/sam/gclk_impl.hpp.in b/src/modm/platform/clock/sam/gclk_impl.hpp.in index 0b4c564478..6a2a198802 100644 --- a/src/modm/platform/clock/sam/gclk_impl.hpp.in +++ b/src/modm/platform/clock/sam/gclk_impl.hpp.in @@ -61,7 +61,7 @@ template< uint32_t Core_Hz, uint16_t Vdd_mV=3300 > uint32_t GenericClockController::setFlashLatency() { -%% if device_family == "e5x": +%% if target.family == "d5x/e5x": {% raw %} // TODO: move to device files constexpr std::array, 6> waitStates0{{ @@ -99,7 +99,7 @@ GenericClockController::enableDfll48mClosedLoop(uint32_t waitCycles) static_assert(reference < 43_kHz, "DFLL48 reference frequency must be less than 33 kHz"); constexpr auto multiplier = uint16_t(std::round(48_MHz / double(reference))); -%% if device_family == "d2x" +%% if target.family == "d1x/d2x/dax" // Errata 1.2.1: Disable OnDemand mode SYSCTRL->DFLLCTRL.bit.ONDEMAND = 0; // Wait for synchronization @@ -168,7 +168,7 @@ GenericClockController::enableDfll48mClosedLoop(uint32_t waitCycles) return waitCycles > 0; } -%% if device_family == "d2x" +%% if target.family == "d1x/d2x/dax" template< ClockPeripheral peripheral > void GenericClockController::connect(ClockGenerator clockGen) @@ -196,7 +196,7 @@ GenericClockController::sync(ClockGenerator) sync(); } -%% elif device_family == "e5x" +%% elif target.family == "d5x/e5x" void GenericClockController::sync() { @@ -225,18 +225,18 @@ GenericClockController::connect(ClockGenerator clockGen) template bool -%% if device_family == "e5x" +%% if target.family == "d5x/e5x" GenericClockController::enableExternalCrystal(Xosc clock, uint32_t waitCycles) %% else GenericClockController::enableExternalCrystal(uint32_t waitCycles) %% endif { -%% if device_family == "e5x" +%% if target.family == "d5x/e5x" %% set reg="OSCCTRL->XOSCCTRL[int(clock)]" %% set prefix="OSCCTRL_XOSCCTRL" %% set status="OSCCTRL->STATUS.reg & (OSCCTRL_STATUS_XOSCRDY0 << int(clock))" PeripheralClock::enable(); -%% elif device_family == "d2x" +%% elif target.family == "d1x/d2x/dax" %% set reg="SYSCTRL->XOSC" %% set prefix="SYSCTRL_XOSC" %% set status="SYSCTRL->PCLKSR.bit.XOSCRDY" @@ -245,7 +245,7 @@ GenericClockController::enableExternalCrystal(uint32_t waitCycles) {{reg}}.bit.STARTUP = uint32_t(startupTime); {{reg}}.bit.XTALEN = 1; // Automatic gain control can only be enabled when the crystal is running -%% if device_family == "e5x" +%% if target.family == "d5x/e5x" {{reg}}.bit.ENALC = 0; if constexpr (frequency <= 8'000'000) { {{reg}}.bit.IMULT = 0x3; @@ -281,7 +281,7 @@ GenericClockController::enableExternalCrystal(uint32_t waitCycles) {{reg}}.bit.ENABLE = 1; while(!({{status}}) && --waitCycles); // Enable automatic gain control on success -%% if device_family == "e5x" +%% if target.family == "d5x/e5x" {{reg}}.bit.ENALC = waitCycles > 0; %% else {{reg}}.bit.AMPGC = waitCycles > 0; @@ -290,17 +290,17 @@ GenericClockController::enableExternalCrystal(uint32_t waitCycles) } bool -%% if device_family == "e5x" +%% if target.family == "d5x/e5x" GenericClockController::enableExternalClock(Xosc clock, uint32_t waitCycles) %% else GenericClockController::enableExternalClock(uint32_t waitCycles) %% endif { -%% if device_family == "e5x" +%% if target.family == "d5x/e5x" %% set reg="OSCCTRL->XOSCCTRL[int(clock)]" %% set status="OSCCTRL->STATUS.reg & (OSCCTRL_STATUS_XOSCRDY0 << int(clock))" PeripheralClock::enable(); -%% elif device_family == "d2x" +%% elif target.family == "d1x/d2x/dax" %% set reg="SYSCTRL->XOSC" %% set status="SYSCTRL->PCLKSR.bit.XOSCRDY" PeripheralClock::enable(); @@ -318,7 +318,7 @@ GenericClockController::enableExternalClock(uint32_t waitCycles) bool GenericClockController::enableExternalCrystal32k(Xosc32StartupTime time) { -%% if device_family == "d2x" +%% if target.family == "d1x/d2x/dax" %% set reg="SYSCTRL->XOSC32K" %% set status="SYSCTRL->PCLKSR.bit.XOSC32KRDY" PeripheralClock::enable(); @@ -329,7 +329,7 @@ GenericClockController::enableExternalCrystal32k(Xosc32StartupTime time) %% endif // force oscillator start even if no clock sink is using it yet {{reg}}.bit.ONDEMAND = 0; -%% if device_family == "d2x" +%% if target.family == "d1x/d2x/dax" // disable non-functional automatic gain control, see errata 1.1.1 {{reg}}.bit.AAMPEN = 0; %% endif @@ -346,7 +346,7 @@ GenericClockController::enableExternalCrystal32k(Xosc32StartupTime time) bool GenericClockController::enableExternalClock32k() { -%% if device_family == "d2x" +%% if target.family == "d1x/d2x/dax" %% set reg="SYSCTRL->XOSC32K" %% set status="SYSCTRL->PCLKSR.bit.XOSC32KRDY" PeripheralClock::enable(); @@ -459,7 +459,7 @@ findDpllConfigXosc(double xoscClock, double target, uint16_t tolerance_ppm [[may template bool -%% if device_family == "e5x" +%% if target.family == "d5x/e5x" GenericClockController::enableDpll(DpllInstance instance) %% else GenericClockController::enableDpll() @@ -479,7 +479,7 @@ GenericClockController::enableDpll() }(); static_assert(std::abs((config.bestOutputFrequency / output) - 1) <= tolerance_ppm, "DPLL clock tolerance exceeded"); -%% if device_family == "e5x" +%% if target.family == "d5x/e5x" return enableDpll(instance); %% else return enableDpll(); @@ -489,7 +489,7 @@ GenericClockController::enableDpll() /// Enable PLL with manual configuration template bool -%% if device_family == "e5x" +%% if target.family == "d5x/e5x" GenericClockController::enableDpll(DpllInstance instance) %% else GenericClockController::enableDpll() @@ -514,13 +514,13 @@ GenericClockController::enableDpll() static_assert(output >= DpllConfig::MinOutput, "DPLL output frequency is too low"); static_assert(output <= DpllConfig::MaxOutput, "DPLL output frequency is too high"); -%% if device_family == "d2x" +%% if target.family == "d1x/d2x/dax" %% set dpll_peripheral="SYSCTRL" %% else %% set dpll_peripheral="OSCCTRL" %% endif -%% if device_family == "e5x" +%% if target.family == "d5x/e5x" %% set instance="Dpll[int(instance)]." %% else %% set instance="" @@ -530,14 +530,14 @@ GenericClockController::enableDpll() {{dpll_peripheral}}->{{instance}}DPLLRATIO.bit.LDRFRAC = config.fractionalMultiplier; {{dpll_peripheral}}->{{instance}}DPLLCTRLB.bit.DIV = config.xoscDivider; {{dpll_peripheral}}->{{instance}}DPLLCTRLB.bit.REFCLK = static_cast(source.reference); -%% if device_family != "d2x" +%% if target.family != "d1x/d2x/dax" while({{dpll_peripheral}}->{{instance}}DPLLSYNCBUSY.bit.DPLLRATIO); %% endif // force oscillator start even if no clock sink is using it yet {{dpll_peripheral}}->{{instance}}DPLLCTRLA.bit.ONDEMAND = 0; {{dpll_peripheral}}->{{instance}}DPLLCTRLA.bit.ENABLE = 1; -%% if device_family == "d2x" +%% if target.family == "d1x/d2x/dax" while(!{{dpll_peripheral}}->{{instance}}DPLLSTATUS.bit.ENABLE); %% else while({{dpll_peripheral}}->{{instance}}DPLLSYNCBUSY.bit.ENABLE); @@ -549,14 +549,14 @@ GenericClockController::enableDpll() } void -%% if device_family == "e5x" +%% if target.family == "d5x/e5x" GenericClockController::disableDpll(DpllInstance instance) %% else GenericClockController::disableDpll() %% endif { {{dpll_peripheral}}->{{instance}}DPLLCTRLA.bit.ENABLE = 0; -%% if device_family == "d2x" +%% if target.family == "d1x/d2x/dax" while({{dpll_peripheral}}->{{instance}}DPLLSTATUS.bit.ENABLE); %% else while({{dpll_peripheral}}->{{instance}}DPLLSYNCBUSY.bit.ENABLE); @@ -573,7 +573,7 @@ GenericClockController::enableGenerator() // TODO: check individual divider limits for each generator instance static_assert(config.divider != 0 && dividerReg <= std::numeric_limits::max(), "Divider out of range"); -%% if device_family == "d2x" +%% if target.family == "d1x/d2x/dax" constexpr auto gen = static_cast(clockGen); GCLK->GENDIV.reg = GCLK_GENDIV_ID(gen) | @@ -613,7 +613,7 @@ template void GenericClockController::disableGenerator() { -%% if device_family == "d2x" +%% if target.family == "d1x/d2x/dax" GCLK->GENCTRL.reg = GCLK_GENCTRL_ID(static_cast(clockGen)); %% else GCLK->GENCTRL[static_cast(clockGen)].bit.GENEN = false; diff --git a/src/modm/platform/clock/sam/module.lb b/src/modm/platform/clock/sam/module.lb index d7a42b9c44..a710bf3923 100644 --- a/src/modm/platform/clock/sam/module.lb +++ b/src/modm/platform/clock/sam/module.lb @@ -27,27 +27,33 @@ def build(env): target = env[":target"].identifier driver = env[":target"].get_driver("gclk") - if target.family in ["d", "e"] and target.series.startswith("5"): - device_family = "e5x" - elif target.family == "d" and target.series.startswith("2"): - device_family = "d2x" - else: + if target.family not in ["d1x/d2x/dax", "d5x/e5x"]: raise RuntimeError("Unsupported device") - if device_family == "e5x": + if target.family == "d5x/e5x": boot_frequency = "48'000'000" - else: # d2x + else: # d1x/d2x/dax boot_frequency = "1'000'000" + clock_map = env.query(":cmsis:device:clock-map") + if target.series == "d21": + # Variant "l" devices have one comparator with instance number "1" and one without. + # To be compatible with the gpio data, instance number "0" is used for the first. + if target.variant == "l": + ac0 = clock_map[('AC', '')] + del clock_map[('AC', '')] + clock_map[('AC', '0')] = ac0 + elif ('AC', '1') in clock_map: + del clock_map[('AC', '1')] + env.substitutions = { "target": target, "boot_frequency": boot_frequency, - "device_family": device_family, - "clock_map": env.query(":cmsis:device:clock-map"), + "clock_map": clock_map, "peripheral_clocks": driver["clock"], "clock_sources": driver["source"], "generator_count": int(driver["generators"][0]), - "has_dpll": device_family in ["d2x", "e5x"] + "has_dpll": True # True for all supported devices for now } env.outbasepath = "modm/src/modm/platform/clock" env.template("gclk.hpp.in") diff --git a/src/modm/platform/clock/sam_pmc/clockgen.cpp.in b/src/modm/platform/clock/sam_pmc/clockgen.cpp.in index 10da4cd2f3..de949ac750 100644 --- a/src/modm/platform/clock/sam_pmc/clockgen.cpp.in +++ b/src/modm/platform/clock/sam_pmc/clockgen.cpp.in @@ -70,10 +70,10 @@ ClockGen::masterClkFrequency() return mainClkFrequency() / div; case MasterClkSource::PLLA_CLK: return pllAFrequency() / div; -%% if target.family in ["g"] +%% if target.family == "g5x" case MasterClkSource::PLLB_CLK: return pllBFrequency() / div; -%% elif target.series[0] == "7" +%% elif target.family == "e7x/s7x/v7x" case MasterClkSource::UPLL_CLK: return 240'000'000; // UPLLDIV2 %% endif @@ -112,10 +112,10 @@ uint32_t ClockGen::pllAFrequency() { uint32_t mul = ((PMC->CKGR_PLLAR & CKGR_PLLAR_MULA_Msk) >> CKGR_PLLAR_MULA_Pos) + 1; -%% if target.family in ["g"] +%% if target.family == "g5x" uint32_t freq = SlowClkFreqHz * mul; if(PMC->PMC_MCKR & PMC_MCKR_PLLADIV2) freq /= 2; -%% elif target.series[0] == "7" +%% elif target.family == "e7x/s7x/v7x" uint32_t freq = mainClkFrequency() * mul; const auto diva = ((PMC->CKGR_PLLAR & CKGR_PLLAR_DIVA_Msk) >> CKGR_PLLAR_DIVA_Pos); if (diva == 0) return 0; // PLLA is disabled @@ -124,7 +124,7 @@ ClockGen::pllAFrequency() return freq; } -%% if target.family in ["g"] +%% if target.family == "g5x" uint32_t ClockGen::pllBFrequency() { diff --git a/src/modm/platform/clock/sam_pmc/clockgen.hpp.in b/src/modm/platform/clock/sam_pmc/clockgen.hpp.in index 4cba706312..a8f4657a95 100644 --- a/src/modm/platform/clock/sam_pmc/clockgen.hpp.in +++ b/src/modm/platform/clock/sam_pmc/clockgen.hpp.in @@ -36,9 +36,9 @@ MasterClkSource : uint32_t SLOW_CLK = PMC_MCKR_CSS_SLOW_CLK_Val, MAIN_CLK = PMC_MCKR_CSS_MAIN_CLK_Val, PLLA_CLK = PMC_MCKR_CSS_PLLA_CLK_Val, -%% if target.family in ["g"] +%% if target.family == "g5x" PLLB_CLK = PMC_MCKR_CSS_PLLB_CLK_Val, -%% elif target.series[0] == "7" +%% elif target.family == "e7x/s7x/v7x" UPLL_CLK = PMC_MCKR_CSS_UPLL_CLK_Val, %% endif }; @@ -60,7 +60,7 @@ enum class MasterClkDivider : uint8_t { Div1 = 0, -%% if target.series[0] == "7" +%% if target.family == "e7x/s7x/v7x" Div2 = PMC_MCKR_MDIV_PCK_DIV2_Val, Div4 = PMC_MCKR_MDIV_PCK_DIV4_Val, Div3 = PMC_MCKR_MDIV_PCK_DIV3_Val, @@ -123,7 +123,7 @@ ClockPeripheral : uint32_t Tc10 = ID_TC3_CHANNEL1, Tc11 = ID_TC3_CHANNEL2, #endif -%% if target.family in ["g"] +%% if target.family == "g5x" Pdmic0 = ID_PDMIC0, Pdmic1 = ID_PDMIC1, Mem2Mem = ID_MEM2MEM, @@ -139,7 +139,7 @@ ClockPeripheral : uint32_t Flexcom5 = ID_FLEXCOM5, Flexcom6 = ID_FLEXCOM6, Flexcom7 = ID_FLEXCOM7, -%% elif target.series[0] == "7" +%% elif target.family == "e7x/s7x/v7x" Xdmac = ID_XDMAC, #ifdef ID_UART0 Uart0 = ID_UART0, @@ -216,7 +216,7 @@ ClockPeripheral : uint32_t %% endif }; -%% if target.series[0] == "7" +%% if target.family == "e7x/s7x/v7x" enum class UtmiRefClk : uint32_t { @@ -277,13 +277,13 @@ public: static void enablePllA(uint32_t wait_cycles = 50); -%% if target.family in ["g"] +%% if target.family == "g5x" template static void enablePllB(uint32_t wait_cycles = 50); %% endif -%% if target.series[0] == "7" +%% if target.family == "e7x/s7x/v7x" template static void enableUPll(uint32_t wait_cycles = 50); @@ -314,7 +314,7 @@ public: static uint32_t pllAFrequency(); -%% if target.family in ["g"] +%% if target.family == "g5x" /** Returns the configured frequency of PLL B output */ static uint32_t pllBFrequency(); diff --git a/src/modm/platform/clock/sam_pmc/clockgen_impl.hpp.in b/src/modm/platform/clock/sam_pmc/clockgen_impl.hpp.in index 32b49a1430..e3b05ddee7 100644 --- a/src/modm/platform/clock/sam_pmc/clockgen_impl.hpp.in +++ b/src/modm/platform/clock/sam_pmc/clockgen_impl.hpp.in @@ -49,11 +49,11 @@ ClockGen::selectMasterClk() { // Datasheet says when selecting PLL as source, write PRES first, otherwise // write CSS first. -%% if target.family in ["g"] +%% if target.family == "g5x" static_assert(divider == MasterClkDivider::Div1, "Divider for master clock is not supported"); constexpr bool isPll = (src == MasterClkSource::PLLA_CLK || src == MasterClkSource::PLLB_CLK); -%% elif target.series[0] == "7" +%% elif target.family == "e7x/s7x/v7x" constexpr bool isPll = (src == MasterClkSource::PLLA_CLK || src == MasterClkSource::UPLL_CLK); %% endif @@ -61,7 +61,7 @@ ClockGen::selectMasterClk() if constexpr (isPll) { PMC->PMC_MCKR = (PMC->PMC_MCKR & ~PMC_MCKR_PRES_Msk) | PMC_MCKR_PRES((uint32_t)pres); while(!(PMC->PMC_SR & PMC_SR_MCKRDY)) {} -%% if target.series[0] == "7" +%% if target.family == "e7x/s7x/v7x" PMC->PMC_MCKR = (PMC->PMC_MCKR & ~PMC_MCKR_MDIV_Msk) | PMC_MCKR_MDIV(uint32_t(divider)); while(!(PMC->PMC_SR & PMC_SR_MCKRDY)) {} %% endif @@ -72,7 +72,7 @@ ClockGen::selectMasterClk() while(!(PMC->PMC_SR & PMC_SR_MCKRDY)) {} PMC->PMC_MCKR = (PMC->PMC_MCKR & ~PMC_MCKR_PRES_Msk) | PMC_MCKR_PRES((uint32_t)pres); while(!(PMC->PMC_SR & PMC_SR_MCKRDY)) {} -%% if target.series[0] == "7" +%% if target.family == "e7x/s7x/v7x" PMC->PMC_MCKR = (PMC->PMC_MCKR & ~PMC_MCKR_MDIV_Msk) | PMC_MCKR_MDIV(uint32_t(divider)); while(!(PMC->PMC_SR & PMC_SR_MCKRDY)) {} %% endif @@ -83,10 +83,10 @@ template void ClockGen::enablePllA(uint32_t wait_cycles) { -%% if target.family in ["g"] +%% if target.family == "g5x" static_assert(9 <= multiplier && multiplier <= 7501, "Valid PLL MUL range is 9-7501"); static_assert(divider == 1, "PLL divider not supported"); -%% elif target.series[0] == "7" +%% elif target.family == "e7x/s7x/v7x" static_assert(1 <= multiplier && multiplier <= 62, "Valid PLL MUL range is 1-62"); static_assert(1 <= divider && divider <= 255, "Valid PLL DIV range is 1-255"); %% endif @@ -94,9 +94,9 @@ ClockGen::enablePllA(uint32_t wait_cycles) PMC->CKGR_PLLAR = CKGR_PLLAR_MULA(multiplier-1) | CKGR_PLLAR_PLLACOUNT(wait_cycles) | -%% if target.family in ["g"] +%% if target.family == "g5x" CKGR_PLLAR_PLLAEN(1); -%% elif target.series[0] == "7" +%% elif target.family == "e7x/s7x/v7x" CKGR_PLLAR_ONE | CKGR_PLLAR_DIVA(divider); %% endif @@ -104,7 +104,7 @@ ClockGen::enablePllA(uint32_t wait_cycles) while(!(PMC->PMC_SR & PMC_SR_LOCKA)) {} } -%% if target.family in ["g"] +%% if target.family == "g5x" template void ClockGen::enablePllB(uint32_t wait_cycles) @@ -119,7 +119,7 @@ ClockGen::enablePllB(uint32_t wait_cycles) } %% endif -%% if target.series[0] == "7" +%% if target.family == "e7x/s7x/v7x" template void ClockGen::enableUPll(uint32_t wait_cycles) diff --git a/src/modm/platform/clock/systick/module.lb b/src/modm/platform/clock/systick/module.lb index 9793e21ee9..e1b7d5b908 100644 --- a/src/modm/platform/clock/systick/module.lb +++ b/src/modm/platform/clock/systick/module.lb @@ -41,12 +41,12 @@ def build(env): # SysTick clock prescaler is dynamically chosen as /1 or /8 div = 8 # SAMD5x/E5x: Prescaler not implemented - if target.platform == "sam" and target.family in ["d", "e"] and target.series[0] == "5": + if target.platform == "sam" and target.family == "d5x/e5x": div = 1 # systick clock is too fast to run at 4 Hz, increase frequency freq = 8 # SAMD2x: Prescaler not implemented - elif target.platform == "sam" and target.family in ["d"]: + elif target.platform == "sam" and target.family == "d1x/d2x/dax": div = 1 # H742/43: Prescaler not implemented in revY elif target.family == "h7" and target.name in ["42", "43", "50", "53"] and target.revision == "y": diff --git a/src/modm/platform/core/sam/module.lb b/src/modm/platform/core/sam/module.lb index 08e871c587..98257adf99 100644 --- a/src/modm/platform/core/sam/module.lb +++ b/src/modm/platform/core/sam/module.lb @@ -35,14 +35,11 @@ def build(env): # delay code that must be tuned for each family # (cycles per loop, setup cost in loops, max cpu frequency) tuning = { - "d2": (3, 4, 48), # CM0 tested on D21 in RAM - "d5": (4, 4, 120), # CM4 tested on E54 in RAM - "e5": (4, 4, 120), # CM4 tested on E54 in RAM - "g5": (6, 4, 120), # G55 - "e7": (4, 4, 300), # CM7 tested on V71 - "s7": (4, 4, 300), # CM7 tested on V71 - "v7": (4, 4, 300), # CM7 tested on V71 - }[target.family + target.series[0]] + "d1x/d2x/dax": (3, 4, 48), # CM0 tested on D21 in RAM + "d5x/e5x": (4, 4, 120), # CM4 tested on E54 in RAM + "g5x": (6, 4, 120), # G55 + "e7x/s7x/v7x": (4, 4, 300), # CM7 tested on V71 + }[target.family] # us_shift is an optimization to limit error via fractional math us_shift = 32 - math.ceil(math.log2(tuning[2] * 1e6)) diff --git a/src/modm/platform/core/sam/startup_platform.c.in b/src/modm/platform/core/sam/startup_platform.c.in index 5c99d8d829..5c6c5fd1d3 100644 --- a/src/modm/platform/core/sam/startup_platform.c.in +++ b/src/modm/platform/core/sam/startup_platform.c.in @@ -24,8 +24,7 @@ void __modm_initialize_platform(void) { -%% if target.family == "d" -%% if target.series == "21" +%% if target.series == "d21" // Overwriting the default value of the NVMCTRL.CTRLB.MANW bit (errata reference 13134) NVMCTRL->CTRLB.bit.MANW = 1; @@ -41,15 +40,5 @@ __modm_initialize_platform(void) DMAC->QOSCTRL.bit.DQOS = 2; DMAC->QOSCTRL.bit.FQOS = 2; DMAC->QOSCTRL.bit.WRBQOS = 2; - -%% elif target.series == "21" -%% endif - -%% elif target.family == "l" -%% if target.series == "21" %% endif - -%% elif target.family == "g" -%% endif - } diff --git a/src/modm/platform/gpio/sam/config.hpp.in b/src/modm/platform/gpio/sam/config.hpp.in index c9ec77f860..7e14305cd5 100644 --- a/src/modm/platform/gpio/sam/config.hpp.in +++ b/src/modm/platform/gpio/sam/config.hpp.in @@ -37,7 +37,7 @@ struct Peripherals struct {{ name }} { %% for signal, index_list in peripheral["signals"].items() -%% if not index_list or (name in ["Adc", "Afec"] and not is_d5x_e5x) +%% if not index_list or (name in ["Adc", "Afec"] and not target["family"] == "d5x/e5x") struct {{ signal }} {}; %% else template @@ -73,7 +73,7 @@ struct Peripherals::{{ name }}<{{ instance }}>::{{ signal }} {}; %% endif %% endfor %% endfor -%% elif name not in ["Adc", "Afec"] or is_d5x_e5x +%% elif name not in ["Adc", "Afec"] or target["family"] == "d5x/e5x" %% for signal, index_list in peripheral["signals"].items() %% for index in index_list template<> @@ -103,7 +103,7 @@ struct {{ gpio["port"] ~ gpio["pin"] }} %% else using peripheral = Peripherals::{{ signal["peripheral"] }}; %% endif - %% if "index" in signal and (signal["peripheral"] not in ["Adc", "Afec"] or is_d5x_e5x) + %% if "index" in signal and (signal["peripheral"] not in ["Adc", "Afec"] or target["family"] == "d5x/e5x") using signal = peripheral::{{ signal["name"] }}<{{ signal["index"] }}>; %% else using signal = peripheral::{{ signal["name"] }}; diff --git a/src/modm/platform/gpio/sam/enable.cpp.in b/src/modm/platform/gpio/sam/enable.cpp.in index df793bd33f..f73a33a91d 100644 --- a/src/modm/platform/gpio/sam/enable.cpp.in +++ b/src/modm/platform/gpio/sam/enable.cpp.in @@ -16,8 +16,7 @@ void modm_gpio_enable(void) { -%% if target["family"] in ["g", "v"] or target["series"][0] == "7" - +%% if target["family"] in ["g5x", "e7x/s7x/v7x"] PMC->PMC_PCER0 = %% for port in options.enable_ports (1<) | ...); }; -%% if target["family"] in ["g", "v"] or target["series"][0] == "7" +%% if target["family"] in ["g5x", "e7x/s7x/v7x"] template struct PinMuxMixin @@ -473,7 +473,7 @@ public: inline static bool read() { -%% if target["family"] in ["g", "v"] or target["series"][0] == "7" +%% if target["family"] in ["g5x", "e7x/s7x/v7x"] return Base::template readPortReg(PIO_PDSR_OFFSET); %% else return Base::template readPortReg(PORT_IN_OFFSET); @@ -483,7 +483,7 @@ public: inline static bool isSet() { -%% if target["family"] in ["g", "v"] or target["series"][0] == "7" +%% if target["family"] in ["g5x", "e7x/s7x/v7x"] return Base::template readPortReg(PIO_ODSR_OFFSET); %% else return Base::template readPortReg(PORT_OUT_OFFSET); @@ -547,7 +547,7 @@ struct Gpio::As : public Gpio connect() { -%% if target["family"] in ["g", "v"] or target["series"][0] == "7" +%% if target["family"] in ["g5x", "e7x/s7x/v7x"] // X1 denotes an "extra function", such as an ADC pin, which is not // enabled by the PIO ABCD register. static_assert(PinSignal::function != PinFunction::X1, diff --git a/src/modm/platform/uart/sam/uart.cpp.in b/src/modm/platform/uart/sam/uart.cpp.in index 3fc610118e..e9c06705bb 100644 --- a/src/modm/platform/uart/sam/uart.cpp.in +++ b/src/modm/platform/uart/sam/uart.cpp.in @@ -16,7 +16,7 @@ %% set name="{}{}".format(type.capitalize(), id) %% set reg=name.upper() -%% if type == "usart" and target.family == "e" and target.variant == "b" +%% if type == "usart" and target.series == "e70" and target.variant == "b" %% set reg_suffix="_USART" %% else %% set reg_suffix="" diff --git a/src/modm/platform/uart/sam/uart.hpp.in b/src/modm/platform/uart/sam/uart.hpp.in index 5cff5f6351..598f336bac 100644 --- a/src/modm/platform/uart/sam/uart.hpp.in +++ b/src/modm/platform/uart/sam/uart.hpp.in @@ -20,7 +20,7 @@ %% set name="{}{}".format(type.capitalize(), id) %% set reg=name.upper() -%% if type == "usart" and target.family == "e" and target.variant == "b" +%% if type == "usart" and target.series == "e70" and target.variant == "b" %% set reg_suffix="_USART" %% else %% set reg_suffix="" diff --git a/src/modm/platform/uart/sam/uart_base.hpp.in b/src/modm/platform/uart/sam/uart_base.hpp.in index cde1297e70..fdd570df87 100644 --- a/src/modm/platform/uart/sam/uart_base.hpp.in +++ b/src/modm/platform/uart/sam/uart_base.hpp.in @@ -24,7 +24,7 @@ public: enum class Parity : uint32_t { %% if type == "usart" -%% if target.family == "e" and target.variant == "b" +%% if target.series == "e70" and target.variant == "b" Disabled = US_MR_USART_PAR_NO_Val, Even = US_MR_USART_PAR_EVEN_Val, Odd = US_MR_USART_PAR_ODD_Val, diff --git a/src/modm/platform/usb/sam/usb.hpp.in b/src/modm/platform/usb/sam/usb.hpp.in index 3b15040441..5db79081a8 100644 --- a/src/modm/platform/usb/sam/usb.hpp.in +++ b/src/modm/platform/usb/sam/usb.hpp.in @@ -28,7 +28,7 @@ public: static void initialize(uint8_t priority=3) { -%% if target["family"] in ["g"] +%% if target["family"] == "g5x" // only the USB device mode is supported for now static_assert(modm::Tolerance::isValueInTolerance(48_MHz, SystemClock::Usb, 0.25_pct), "The USB clock frequency must be within 0.25\% of 48MHz!"); @@ -44,7 +44,7 @@ public: %% else static_assert(SystemClock::Usb == 48_MHz, "Usb must have a 48MHz clock!"); PeripheralClock::enable(); -%% if target["series"][0] == "5" +%% if target["family"] == "d5x/e5x" NVIC_SetPriority(USB_0_IRQn, priority); NVIC_SetPriority(USB_1_IRQn, priority); NVIC_SetPriority(USB_2_IRQn, priority); @@ -58,7 +58,7 @@ public: // SAMG does not provide a connect method for USB. It's not defined in the SVD, // and the USB pins are fixed. Instead, calling Usb::initialize() switches the // IO pin function to the USB controller. -%% if target["family"] not in ["g"] +%% if target["family"] != "g5x" template static void connect() diff --git a/tools/scripts/generate_hal_matrix.py b/tools/scripts/generate_hal_matrix.py index b4ccff0de3..d31d889993 100755 --- a/tools/scripts/generate_hal_matrix.py +++ b/tools/scripts/generate_hal_matrix.py @@ -41,7 +41,7 @@ def hal_get_modules(): short_id.naming_schema = "{platform}-{family}" elif target.platform == "sam": - short_id.naming_schema = "{platform}{family}{series}" + short_id.naming_schema = "{platform}{series}" short_id.set("platform", target.platform) # invalidate caches minimal_targets[short_id.string].append(target) @@ -203,7 +203,11 @@ def hal_create_table(targets, platforms, common_table=False): {% endfor %} Peripheral {% for fam in families -%} +{% if fam[0] == "sam" -%} +{{ fam[1] | upper | replace("X", "x") | replace("/", "
") }} +{% else -%} {{ fam[1] | capitalize }} +{% endif -%} {% endfor %} {%- for per in pers | sort %} {{ per }} diff --git a/tools/scripts/generate_module_docs.py b/tools/scripts/generate_module_docs.py index d90a3631f6..c346bb4e47 100755 --- a/tools/scripts/generate_module_docs.py +++ b/tools/scripts/generate_module_docs.py @@ -160,7 +160,7 @@ def replace(text, key, content): return re.sub(r"# {0}.*?# /{0}".format(key), "# {0}\n{1}\n# /{0}".format(key, content), text, flags=re.DOTALL | re.MULTILINE) def url_name(name): - for c in ":., ({": name = name.replace(c, "-"); + for c in ":.,/ ({": name = name.replace(c, "-"); for c in "})": name = name.replace(c, ""); return name From 8a0ac8a8a4bfd00ab0f95d83c7550d36a45fec17 Mon Sep 17 00:00:00 2001 From: Christopher Durand Date: Wed, 31 Aug 2022 05:47:16 +0200 Subject: [PATCH 28/35] [ci] Split SAM hal compile all job --- .github/workflows/compile-all.yml | 58 +++++++++++++++++++++++++++++-- 1 file changed, 55 insertions(+), 3 deletions(-) diff --git a/.github/workflows/compile-all.yml b/.github/workflows/compile-all.yml index 226a3b2d2d..ff89e15407 100644 --- a/.github/workflows/compile-all.yml +++ b/.github/workflows/compile-all.yml @@ -31,7 +31,7 @@ jobs: name: avr-compile-all path: test/all/log - sam-compile-all: + sam-d0x-d1x-d2x-compile-all: if: github.event.label.name == 'ci:hal' runs-on: ubuntu-20.04 container: @@ -47,9 +47,61 @@ jobs: - name: Update lbuild run: | pip3 install --upgrade --upgrade-strategy=eager modm - - name: Compile HAL for all SAM + - name: Compile HAL for SAMD0x, SAMD1x, SAMD2x run: | - (cd test/all && python3 run_all.py sam --quick-remaining) + (cd test/all && python3 run_all.py samd0 samd1 samd2 --quick-remaining) + - name: Upload log artifacts + if: always() + uses: actions/upload-artifact@v2 + with: + name: sam-compile-all + path: test/all/log + + sam-x5x-compile-all: + if: github.event.label.name == 'ci:hal' + runs-on: ubuntu-20.04 + container: + image: ghcr.io/modm-ext/modm-build-cortex-m:2022-09-27 + steps: + - name: Check out repository + uses: actions/checkout@v3 + with: + submodules: 'recursive' + - name: Fix Git permission/ownership problem + run: | + git config --global --add safe.directory /__w/modm/modm + - name: Update lbuild + run: | + pip3 install --upgrade --upgrade-strategy=eager modm + - name: Compile HAL for SAMD5x, SAME5x, SAMG5x + run: | + (cd test/all && python3 run_all.py samd5 same5 samg5 --quick-remaining) + - name: Upload log artifacts + if: always() + uses: actions/upload-artifact@v2 + with: + name: sam-compile-all + path: test/all/log + + sam-x7x-compile-all: + if: github.event.label.name == 'ci:hal' + runs-on: ubuntu-20.04 + container: + image: ghcr.io/modm-ext/modm-build-cortex-m:2022-09-27 + steps: + - name: Check out repository + uses: actions/checkout@v3 + with: + submodules: 'recursive' + - name: Fix Git permission/ownership problem + run: | + git config --global --add safe.directory /__w/modm/modm + - name: Update lbuild + run: | + pip3 install --upgrade --upgrade-strategy=eager modm + - name: Compile HAL for SAME7x, SAMS7x, SAMV7x + run: | + (cd test/all && python3 run_all.py same7 sams7 samv7 --quick-remaining) - name: Upload log artifacts if: always() uses: actions/upload-artifact@v2 From a73ba0940c9fbaf777e65cabfd6604ebf03ccbc9 Mon Sep 17 00:00:00 2001 From: Christopher Durand Date: Fri, 16 Sep 2022 01:19:25 +0200 Subject: [PATCH 29/35] [sam] Fix SERCOM UART pin remapping --- src/modm/platform/uart/sam-sercom/uart.hpp.in | 36 +++++++++++++++++++ .../platform/uart/sam-sercom/uart_base.hpp.in | 36 +++++++++++++++++++ .../platform/uart/sam-sercom/uart_hal.hpp.in | 8 +++++ .../uart/sam-sercom/uart_hal_impl.hpp.in | 15 ++++++-- 4 files changed, 92 insertions(+), 3 deletions(-) diff --git a/src/modm/platform/uart/sam-sercom/uart.hpp.in b/src/modm/platform/uart/sam-sercom/uart.hpp.in index 56e4a3f424..d0170e5b52 100644 --- a/src/modm/platform/uart/sam-sercom/uart.hpp.in +++ b/src/modm/platform/uart/sam-sercom/uart.hpp.in @@ -39,6 +39,40 @@ class {{ name }} : public UartBase, public ::modm::Uart "Rx and Tx cannot use the same signal!"); }; + template + static void + configurePadMapping() + { + constexpr auto rxIndex = detail::get_pad_index_v; + constexpr auto txIndex = detail::get_pad_index_v; + + PeripheralClock>::enable(); + + if constexpr (rxIndex == 0) { + {{ hal }}::setRxPinout(RxPinout::RxPad0); + } else if constexpr (rxIndex == 1) { + {{ hal }}::setRxPinout(RxPinout::RxPad1); + } else if constexpr (rxIndex == 2) { + {{ hal }}::setRxPinout(RxPinout::RxPad2); + } else if constexpr (rxIndex == 3) { + {{ hal }}::setRxPinout(RxPinout::RxPad3); + } else { + // assert is always false + static_assert(!std::is_same_v, "Invalid rx signal"); + } + + if constexpr (txIndex == 0) { + {{ hal }}::setTxPinout(TxPinout::TxPad0_XckPad1); +%% if target.family != "d5x/e5x" + } else if constexpr (txIndex == 2) { + {{ hal }}::setTxPinout(TxPinout::TxPad2_XckPad3); +%% endif + } else { + // assert is always false + static_assert(!std::is_same_v, "Invalid tx signal"); + } + } + public: template< class... Pins > static void @@ -53,6 +87,8 @@ public: 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 {}; + + configurePadMapping(); RxConnector::connect(); TxConnector::connect(); } diff --git a/src/modm/platform/uart/sam-sercom/uart_base.hpp.in b/src/modm/platform/uart/sam-sercom/uart_base.hpp.in index 3d0e0eb723..03aaf96da3 100644 --- a/src/modm/platform/uart/sam-sercom/uart_base.hpp.in +++ b/src/modm/platform/uart/sam-sercom/uart_base.hpp.in @@ -17,6 +17,22 @@ #include #include +/// @cond +namespace modm::platform::detail +{ + template + struct get_pad_index; + + template typename T, int index> + struct get_pad_index> + { + static constexpr int value{index}; + }; + + template + static constexpr auto get_pad_index_v = get_pad_index::value; +} +/// @endcond namespace modm::platform { @@ -36,6 +52,26 @@ public: Odd = 1, Disabled = 2, }; + + enum class RxPinout : uint8_t + { + RxPad0 = 0, + RxPad1 = 1, + RxPad2 = 2, + RxPad3 = 3 + }; + + enum class TxPinout : uint8_t + { + TxPad0_XckPad1 = 0, +%% if target.family != "d5x/e5x" + TxPad2_XckPad3 = 1, +%% endif + TxPad0_RtsTePad2_CtsPad3 = 2, +%% if target.family in ["d5x/e5x", "l1x", "l2x"] + TxPad0_XckPad1_RtsTePad2 = 3 +%% endif + }; }; } // namespace modm::platform diff --git a/src/modm/platform/uart/sam-sercom/uart_hal.hpp.in b/src/modm/platform/uart/sam-sercom/uart_hal.hpp.in index dce1143e6b..833a4f6430 100644 --- a/src/modm/platform/uart/sam-sercom/uart_hal.hpp.in +++ b/src/modm/platform/uart/sam-sercom/uart_hal.hpp.in @@ -108,6 +108,14 @@ public: /// Returns true if data can be written static inline bool isTransmitRegisterEmpty(); + + /// Configure mapping between rx pin functions and IO pads + static inline void + setRxPinout(RxPinout rxPinout); + + /// Configure mapping between tx pin functions and IO pads + static inline void + setTxPinout(TxPinout txPinout); }; } // namespace modm::platform diff --git a/src/modm/platform/uart/sam-sercom/uart_hal_impl.hpp.in b/src/modm/platform/uart/sam-sercom/uart_hal_impl.hpp.in index 622b0a7a6d..8947a40bee 100644 --- a/src/modm/platform/uart/sam-sercom/uart_hal_impl.hpp.in +++ b/src/modm/platform/uart/sam-sercom/uart_hal_impl.hpp.in @@ -62,9 +62,6 @@ void {{ peripheral }}->USART.CTRLA.bit.MODE = 0x1; // Set asynchronous mode {{ peripheral }}->USART.CTRLA.bit.CMODE = 0x0; - // Set rx/tx pins - {{ peripheral }}->USART.CTRLA.bit.RXPO = 0x3; // Pad3 - {{ peripheral }}->USART.CTRLA.bit.TXPO = 0x1; // Pad2; // Set character size to 8 bits {{ peripheral }}->USART.CTRLB.bit.CHSIZE = 0x0; // Set Data order to LSB first @@ -139,4 +136,16 @@ bool return {{ peripheral }}->USART.INTFLAG.bit.DRE; } +void +{{ name }}::setRxPinout(RxPinout rxPinout) +{ + {{ peripheral }}->USART.CTRLA.bit.RXPO = static_cast(rxPinout); +} + +void +{{ name }}::setTxPinout(TxPinout txPinout) +{ + {{ peripheral }}->USART.CTRLA.bit.TXPO = static_cast(txPinout); +} + } // namespace modm::platform From 30b73aa43dc9fa18e37b68a44eb5bbeb62180ceb Mon Sep 17 00:00:00 2001 From: Christopher Durand Date: Fri, 16 Sep 2022 01:20:06 +0200 Subject: [PATCH 30/35] [sam] Fix SAMD1x/D2x/DAx input pull-up configuration setInput(InputType) erroneously reset the type to floating after enabling pull-ups. --- src/modm/platform/gpio/sam/pin.hpp.in | 1 - 1 file changed, 1 deletion(-) diff --git a/src/modm/platform/gpio/sam/pin.hpp.in b/src/modm/platform/gpio/sam/pin.hpp.in index 05f5457e44..73bc609eda 100644 --- a/src/modm/platform/gpio/sam/pin.hpp.in +++ b/src/modm/platform/gpio/sam/pin.hpp.in @@ -379,7 +379,6 @@ public: setInput(InputType type) { configure(type); - setInput(); } static void From 060c22fd9d9b968eaf9d8b0235e59eece8fdf27e Mon Sep 17 00:00:00 2001 From: Christopher Durand Date: Fri, 16 Sep 2022 01:24:29 +0200 Subject: [PATCH 31/35] [board] Add SAMD21 Xplained Pro --- .github/workflows/linux.yml | 2 +- README.md | 5 +- src/modm/board/samd21_xplained_pro/board.hpp | 118 +++++++++++++++++++ src/modm/board/samd21_xplained_pro/board.xml | 14 +++ src/modm/board/samd21_xplained_pro/module.lb | 35 ++++++ 5 files changed, 171 insertions(+), 3 deletions(-) create mode 100644 src/modm/board/samd21_xplained_pro/board.hpp create mode 100644 src/modm/board/samd21_xplained_pro/board.xml create mode 100644 src/modm/board/samd21_xplained_pro/module.lb diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index f73c06cd48..8bdb2c584b 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -92,7 +92,7 @@ jobs: - name: Examples SAMD Devices if: always() run: | - (cd examples && ../tools/scripts/examples_compile.py samd) + (cd examples && ../tools/scripts/examples_compile.py samd samd21_xplained_pro) - name: Examples SAMG Devices if: always() run: | diff --git a/README.md b/README.md index b80d0cf4fb..d549a05b27 100644 --- a/README.md +++ b/README.md @@ -632,15 +632,16 @@ We have out-of-box support for many development boards including documentation. Raspberry Pi Pico SAMD21-MINI +SAMD21-XPLAINED-PRO SAME54-XPLAINED-PRO SAMG55-XPLAINED-PRO -SAMV71-XPLAINED-ULTRA +SAMV71-XPLAINED-ULTRA Smart Response XE STM32-F4VE STM32F030-DEMO -THINGPLUS-RP2040 +THINGPLUS-RP2040 diff --git a/src/modm/board/samd21_xplained_pro/board.hpp b/src/modm/board/samd21_xplained_pro/board.hpp new file mode 100644 index 0000000000..4b4ce82b84 --- /dev/null +++ b/src/modm/board/samd21_xplained_pro/board.hpp @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2022, Christopher Durand + * + * 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 + +#define MODM_BOARD_HAS_LOGGER + +namespace Board +{ +/// @ingroup modm_board_samd21_xplained_pro +/// @{ +using namespace modm::literals; +using namespace modm::platform; + + +struct SystemClock +{ + static constexpr uint32_t Dfll48m = 48_MHz; + static constexpr uint32_t Xosc32k = 32768_Hz; + + static constexpr uint32_t Frequency = Dfll48m; + static constexpr uint32_t Usb = Dfll48m; + + static constexpr auto ClockGen32kHz = ClockGenerator::Generator2; + + static constexpr uint32_t Sercom3 = Frequency; + static constexpr uint32_t SercomSlow = Xosc32k; + + static bool inline + enable() + { + // Configure GCLK generator 2 with external 32k crystal source + GenericClockController::enableExternalCrystal32k(Xosc32StartupTime::Start_500ms); + GenericClockController::enableGenerator(); + + // generate 48 MHz from 32768 Hz crystal reference + GenericClockController::connect(ClockGen32kHz); + GenericClockController::enableDfll48mClosedLoop(); + + GenericClockController::setFlashLatency(); + GenericClockController::setSystemClock(); + GenericClockController::updateCoreFrequency(); + + GenericClockController::connect(ClockGenerator::System); + + GenericClockController::connect(ClockGenerator::System); + GenericClockController::connect(ClockGen32kHz); + + return true; + } +}; + +using Led0 = GpioB30; +using Button = GpioA15; + +// No SoftwareGpioPort yet for SAM +struct Leds +{ + static constexpr std::size_t width{1}; + + static void setOutput() + { + Led0::setOutput(); + } + + static void write(uint32_t value) + { + Led0::set(value & 1); + } + + static void toggle() + { + Led0::toggle(); + } +}; + +struct Debug +{ + using Uart = Uart3; + using UartTx = GpioA22; + using UartRx = GpioA23; +}; + +using LoggerDevice = modm::IODeviceWrapper; + +inline void +initialize() +{ + SystemClock::enable(); + SysTickTimer::initialize(); + + Debug::Uart::initialize(); + Debug::Uart::connect(); + + Led0::setOutput(modm::Gpio::Low); + + Button::setInput(Button::InputType::PullUp); +} + +inline void initializeUsbFs() +{ + modm::platform::Usb::initialize(); + modm::platform::Usb::connect(); +} +/// @} + +} // namespace Board + diff --git a/src/modm/board/samd21_xplained_pro/board.xml b/src/modm/board/samd21_xplained_pro/board.xml new file mode 100644 index 0000000000..507a259706 --- /dev/null +++ b/src/modm/board/samd21_xplained_pro/board.xml @@ -0,0 +1,14 @@ + + + + ../../../../repo.lb + + + + + + + + modm:board:samd21-xplained-pro + + diff --git a/src/modm/board/samd21_xplained_pro/module.lb b/src/modm/board/samd21_xplained_pro/module.lb new file mode 100644 index 0000000000..359aebb225 --- /dev/null +++ b/src/modm/board/samd21_xplained_pro/module.lb @@ -0,0 +1,35 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# +# Copyright (c) 2021, Jeff McBride +# Copyright (c) 2021-2022, Christopher Durand +# +# 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/. +# ----------------------------------------------------------------------------- + +def init(module): + module.name = ":board:samd21-xplained-pro" + module.description = "Microchip SAMD21 Xplained Pro" + +def prepare(module, options): + if not options[":target"].partname == "samd21j18a-au": + return False + + module.depends(":debug", ":platform:gclk", ":platform:gpio", ":platform:core", ":platform:usb", ":platform:uart:3") + return True + +def build(env): + env.outbasepath = "modm/src/modm/board" + env.substitutions = { + "with_logger": True, + "with_assert": env.has_module(":architecture:assert") + } + env.template("../board.cpp.in", "board.cpp") + env.copy('board.hpp') + + env.outbasepath = "modm/openocd/modm/board/" + env.collect(":build:openocd.source", "board/atmel_samd21_xplained_pro.cfg"); From 9adb9fa5feb7fb369a54642c73fe7906f0073b7c Mon Sep 17 00:00:00 2001 From: Christopher Durand Date: Fri, 16 Sep 2022 01:24:58 +0200 Subject: [PATCH 32/35] [example] Add SAMD21 Xplained Pro blink example --- examples/samd21_xplained_pro/blink/main.cpp | 39 +++++++++++++++++++ .../samd21_xplained_pro/blink/project.xml | 9 +++++ 2 files changed, 48 insertions(+) create mode 100644 examples/samd21_xplained_pro/blink/main.cpp create mode 100644 examples/samd21_xplained_pro/blink/project.xml diff --git a/examples/samd21_xplained_pro/blink/main.cpp b/examples/samd21_xplained_pro/blink/main.cpp new file mode 100644 index 0000000000..90716c8993 --- /dev/null +++ b/examples/samd21_xplained_pro/blink/main.cpp @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2016-2017, 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/. + */ +// ---------------------------------------------------------------------------- + +#include + +using namespace Board; + +int +main() +{ + Board::initialize(); + + // Use the logging streams to print some messages. + // Change MODM_LOG_LEVEL above to enable or disable these messages + MODM_LOG_DEBUG << "debug" << modm::endl; + MODM_LOG_INFO << "info" << modm::endl; + MODM_LOG_WARNING << "warning" << modm::endl; + MODM_LOG_ERROR << "error" << modm::endl; + + uint32_t counter(0); + + while (true) + { + Led0::toggle(); + modm::delay(Button::read() ? 500ms : 100ms); + + MODM_LOG_INFO << "loop: " << counter++ << modm::endl; + } + + return 0; +} diff --git a/examples/samd21_xplained_pro/blink/project.xml b/examples/samd21_xplained_pro/blink/project.xml new file mode 100644 index 0000000000..2c9638f352 --- /dev/null +++ b/examples/samd21_xplained_pro/blink/project.xml @@ -0,0 +1,9 @@ + + modm:samd21-xplained-pro + + + + + modm:build:scons + + From 8c9b4d8f2f7d411e5a0429bbcdecc3fda72964fc Mon Sep 17 00:00:00 2001 From: Christopher Durand Date: Fri, 16 Sep 2022 11:32:03 +0200 Subject: [PATCH 33/35] [example] Add SAMD21 Xplained Pro usb serial example --- .../samd21_xplained_pro/usbserial/main.cpp | 44 +++++++++++++++++++ .../samd21_xplained_pro/usbserial/project.xml | 12 +++++ 2 files changed, 56 insertions(+) create mode 100644 examples/samd21_xplained_pro/usbserial/main.cpp create mode 100644 examples/samd21_xplained_pro/usbserial/project.xml diff --git a/examples/samd21_xplained_pro/usbserial/main.cpp b/examples/samd21_xplained_pro/usbserial/main.cpp new file mode 100644 index 0000000000..2bf24ef589 --- /dev/null +++ b/examples/samd21_xplained_pro/usbserial/main.cpp @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2016-2017, Niklas Hauser + * Copyright (c) 2022, Christopher Durand + * + * 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 +#include + +using namespace Board; + +modm::IODeviceWrapper usb_io_device; +modm::IOStream usb_stream(usb_io_device); + +int +main() +{ + Board::initialize(); + Board::initializeUsbFs(); + + tusb_init(); + + usb_stream << "Hello from USB" << modm::endl; + + uint32_t counter(0); + + modm::PeriodicTimer timer{500ms}; + while (true) + { + tud_task(); + if (timer.execute()) { + Led0::toggle(); + usb_stream << "loop: " << counter++ << modm::endl; + } + } + + return 0; +} diff --git a/examples/samd21_xplained_pro/usbserial/project.xml b/examples/samd21_xplained_pro/usbserial/project.xml new file mode 100644 index 0000000000..8ab1e6a5a9 --- /dev/null +++ b/examples/samd21_xplained_pro/usbserial/project.xml @@ -0,0 +1,12 @@ + + modm:samd21-xplained-pro + + + + + + modm:tinyusb + modm:build:scons + modm:processing:timer + + From 95e3f743d8943598547103d0ef5060f0d547adb6 Mon Sep 17 00:00:00 2001 From: Christopher Durand Date: Thu, 29 Sep 2022 23:17:20 +0200 Subject: [PATCH 34/35] [sam] Fix device header selection In case a header version with a variant suffix and one without exist it was not defined which one was selected. --- ext/microchip/module.lb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ext/microchip/module.lb b/ext/microchip/module.lb index 24f88b87a1..f5522900c3 100644 --- a/ext/microchip/module.lb +++ b/ext/microchip/module.lb @@ -81,6 +81,10 @@ def validate(env): for n in names: define = "__{}__".format(n.upper()) if match is not None and define in match: + # In case of multiple matches the most specific header is selected. + # The one with the matching variant suffix will have the longest name. + if device_define is not None and len(device_define) > len(define): + continue family_file = famfile.relative_to(localpath(".")) device_header = "{}.h".format(n) device_define = define From 83fbc1c7c4b197f521e17ed3ca3dc6e462593442 Mon Sep 17 00:00:00 2001 From: Christopher Durand Date: Thu, 29 Sep 2022 23:39:58 +0200 Subject: [PATCH 35/35] [sam] Do not use deprecated uart defines on x7x b-variant devices --- src/modm/platform/uart/sam/uart.cpp.in | 2 +- src/modm/platform/uart/sam/uart.hpp.in | 2 +- src/modm/platform/uart/sam/uart_base.hpp.in | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/modm/platform/uart/sam/uart.cpp.in b/src/modm/platform/uart/sam/uart.cpp.in index e9c06705bb..24c45a1f07 100644 --- a/src/modm/platform/uart/sam/uart.cpp.in +++ b/src/modm/platform/uart/sam/uart.cpp.in @@ -16,7 +16,7 @@ %% set name="{}{}".format(type.capitalize(), id) %% set reg=name.upper() -%% if type == "usart" and target.series == "e70" and target.variant == "b" +%% if type == "usart" and target.family == "e7x/s7x/v7x" and target.variant == "b" %% set reg_suffix="_USART" %% else %% set reg_suffix="" diff --git a/src/modm/platform/uart/sam/uart.hpp.in b/src/modm/platform/uart/sam/uart.hpp.in index 598f336bac..0d157f1014 100644 --- a/src/modm/platform/uart/sam/uart.hpp.in +++ b/src/modm/platform/uart/sam/uart.hpp.in @@ -20,7 +20,7 @@ %% set name="{}{}".format(type.capitalize(), id) %% set reg=name.upper() -%% if type == "usart" and target.series == "e70" and target.variant == "b" +%% if type == "usart" and target.family == "e7x/s7x/v7x" and target.variant == "b" %% set reg_suffix="_USART" %% else %% set reg_suffix="" diff --git a/src/modm/platform/uart/sam/uart_base.hpp.in b/src/modm/platform/uart/sam/uart_base.hpp.in index fdd570df87..ad5f4123e9 100644 --- a/src/modm/platform/uart/sam/uart_base.hpp.in +++ b/src/modm/platform/uart/sam/uart_base.hpp.in @@ -24,7 +24,7 @@ public: enum class Parity : uint32_t { %% if type == "usart" -%% if target.series == "e70" and target.variant == "b" +%% if target.family == "e7x/s7x/v7x" and target.variant == "b" Disabled = US_MR_USART_PAR_NO_Val, Even = US_MR_USART_PAR_EVEN_Val, Odd = US_MR_USART_PAR_ODD_Val,