From 62b63f5ec6510f0fb67f8eb9a39dee7df715d0e5 Mon Sep 17 00:00:00 2001 From: Niklas Hauser Date: Sat, 20 Feb 2021 21:02:58 +0100 Subject: [PATCH] [uart] Refactor SAM UART driver --- src/modm/platform/uart/sam/module.lb | 21 +----- src/modm/platform/uart/sam/uart.cpp.in | 36 +++++----- src/modm/platform/uart/sam/uart.hpp.in | 27 ++------ src/modm/platform/uart/sam/uart_base.hpp.in | 18 ++--- src/modm/platform/uart/sam/uart_hal.hpp.in | 25 +++---- .../platform/uart/sam/uart_hal_impl.hpp.in | 65 ++++++++++--------- 6 files changed, 73 insertions(+), 119 deletions(-) diff --git a/src/modm/platform/uart/sam/module.lb b/src/modm/platform/uart/sam/module.lb index 40126849d4..853f0184c4 100644 --- a/src/modm/platform/uart/sam/module.lb +++ b/src/modm/platform/uart/sam/module.lb @@ -1,9 +1,7 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- # -# Copyright (c) 2016-2018, Niklas Hauser -# Copyright (c) 2017, Fabian Greif -# Copyright (c) 2017, Erik Henriksson +# Copyright (c) 2020, Erik Henriksson # # This file is part of the modm project. # @@ -30,9 +28,6 @@ class Instance(Module): device = env[":target"].identifier global props props["id"] = self.instance - props["driver"] = self.driver - props["features"] = self.driver["feature"] if "feature" in self.driver else [] - props["uart_name"] = 'Uart' props["sercom_name"] = self.driver["name"].capitalize() env.substitutions = props @@ -43,8 +38,6 @@ class Instance(Module): env.template("uart.hpp.in", "uart_{}.hpp".format(self.instance)) env.template("uart.cpp.in", "uart_{}.cpp".format(self.instance)) - props["instances"].append(self.instance) - def init(module): module.name = ":platform:uart" @@ -52,13 +45,10 @@ def init(module): def prepare(module, options): device = options[":target"] - if not (device.has_driver("sercom:*")): + if not (device.has_driver("sercom:sam")): return False module.depends( - ":architecture:atomic", - ":architecture:interrupt", - ":architecture:register", ":architecture:uart", ":math:algorithm", ":cmsis:device", @@ -67,11 +57,6 @@ def prepare(module, options): global props drivers = options[":target"].get_all_drivers("sercom") - props["extended_driver"] = ("extended" in drivers[0]["type"]) - props["over8_sampling"] = ("feature" in drivers[0]) and ("over8" in drivers[0]["feature"]) - props["tcbgt"] = ("feature" in drivers[0]) and ("tcbgt" in drivers[0]["feature"]) - props["instances"] = [] - for driver in drivers: for instance in driver["instance"]: module.add_submodule(Instance(driver, instance)) @@ -80,8 +65,6 @@ def prepare(module, options): return True def build(env): - device = env[":target"] - global props env.substitutions = props env.outbasepath = "modm/src/modm/platform/uart" diff --git a/src/modm/platform/uart/sam/uart.cpp.in b/src/modm/platform/uart/sam/uart.cpp.in index f50854773f..1c527e4535 100644 --- a/src/modm/platform/uart/sam/uart.cpp.in +++ b/src/modm/platform/uart/sam/uart.cpp.in @@ -1,11 +1,4 @@ /* - * Copyright (c) 2009, Martin Rosekeit - * Copyright (c) 2009-2011, Fabian Greif - * Copyright (c) 2010-2011, 2013, Georgi Grinshpun - * Copyright (c) 2013-2014, Sascha Schade - * Copyright (c) 2013, 2016, Kevin Läufer - * Copyright (c) 2013-2017, Niklas Hauser - * Copyright (c) 2018, Lucas Mösch * Copyright (c) 2020, Erik Henriksson * * This file is part of the modm project. @@ -16,22 +9,25 @@ */ // ---------------------------------------------------------------------------- -%% set name = uart_name ~ id -%% set hal = uart_name ~ "Hal" ~ id +%% set name = "Uart" ~ id +%% set hal = "UartHal" ~ id #include "../device.hpp" #include "uart_hal_{{ id }}.hpp" #include "uart_{{ id }}.hpp" +namespace modm::platform +{ + void -modm::platform::{{ name }}::writeBlocking(uint8_t data) +{{ name }}::writeBlocking(uint8_t data) { while(!{{ hal }}::isTransmitRegisterEmpty()); {{ hal }}::write(data); } void -modm::platform::{{ name }}::writeBlocking(const uint8_t *data, std::size_t length) +{{ name }}::writeBlocking(const uint8_t *data, std::size_t length) { while (length-- != 0) { writeBlocking(*data++); @@ -39,13 +35,13 @@ modm::platform::{{ name }}::writeBlocking(const uint8_t *data, std::size_t lengt } void -modm::platform::{{ name }}::flushWriteBuffer() +{{ name }}::flushWriteBuffer() { return; } bool -modm::platform::{{ name }}::write(uint8_t data) +{{ name }}::write(uint8_t data) { if({{ hal }}::isTransmitRegisterEmpty()) { {{ hal }}::write(data); @@ -56,7 +52,7 @@ modm::platform::{{ name }}::write(uint8_t data) } std::size_t -modm::platform::{{ name }}::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) @@ -69,19 +65,19 @@ modm::platform::{{ name }}::write(const uint8_t *data, std::size_t length) } bool -modm::platform::{{ name }}::isWriteFinished() +{{ name }}::isWriteFinished() { return {{ hal }}::isTransmitRegisterEmpty(); } std::size_t -modm::platform::{{ name }}::discardTransmitBuffer() +{{ name }}::discardTransmitBuffer() { return 0; } bool -modm::platform::{{ name }}::read(uint8_t &data) +{{ name }}::read(uint8_t &data) { if({{ hal }}::isReceiveRegisterNotEmpty()) { {{ hal }}::read(data); @@ -92,7 +88,7 @@ modm::platform::{{ name }}::read(uint8_t &data) } std::size_t -modm::platform::{{ name }}::read(uint8_t *data, std::size_t length) +{{ name }}::read(uint8_t *data, std::size_t length) { (void)length; // avoid compiler warning if(read(*data)) { @@ -103,7 +99,9 @@ modm::platform::{{ name }}::read(uint8_t *data, std::size_t length) } std::size_t -modm::platform::{{ name }}::discardReceiveBuffer() +{{ name }}::discardReceiveBuffer() { return 0; } + +} // namespace modm::platform diff --git a/src/modm/platform/uart/sam/uart.hpp.in b/src/modm/platform/uart/sam/uart.hpp.in index 1f7fbd7682..f7cbf68ee5 100644 --- a/src/modm/platform/uart/sam/uart.hpp.in +++ b/src/modm/platform/uart/sam/uart.hpp.in @@ -1,10 +1,4 @@ /* - * Copyright (c) 2009-2012, Fabian Greif - * Copyright (c) 2010, Martin Rosekeit - * Copyright (c) 2011, Georgi Grinshpun - * Copyright (c) 2011, 2013-2017, Niklas Hauser - * Copyright (c) 2012, Sascha Schade - * Copyright (c) 2013, 2016, Kevin Läufer * Copyright (c) 2020, Erik Henriksson * * This file is part of the modm project. @@ -15,9 +9,8 @@ */ // ---------------------------------------------------------------------------- -%% set hal = uart_name ~ "Hal" ~ id -%% set name = uart_name ~ id -%% set sercom = sercom_name ~ id +%% set hal = "UartHal" ~ id +%% set name = "Uart" ~ id #pragma once @@ -26,17 +19,13 @@ #include "uart_hal_{{ id }}.hpp" #include -namespace modm -{ - -namespace platform +namespace modm::platform { /** - * Universal asynchronous receiver transmitter ({{ uart_name | upper ~ id }}) + * Universal asynchronous receiver transmitter ({{ "Uart" | upper ~ id }}) * - * @author Kevin Laeufer - * @author Niklas Hauser + * @author Erik Henriksson * @ingroup modm_platform_uart modm_platform_uart_{{id}} */ class {{ name }} : public UartBase, public ::modm::Uart @@ -72,7 +61,7 @@ public: static void modm_always_inline initialize(Parity parity = Parity::Disabled) { - {{ hal }}::initialize(parity); + {{ hal }}::initialize(parity); {{ hal }}::setTransmitterEnable(true); {{ hal }}::setReceiverEnable(true); } @@ -108,6 +97,4 @@ public: discardReceiveBuffer(); }; -} // namespace platform - -} // namespace modm +} // namespace modm::platform diff --git a/src/modm/platform/uart/sam/uart_base.hpp.in b/src/modm/platform/uart/sam/uart_base.hpp.in index 1ee1081452..3d0e0eb723 100644 --- a/src/modm/platform/uart/sam/uart_base.hpp.in +++ b/src/modm/platform/uart/sam/uart_base.hpp.in @@ -1,7 +1,4 @@ /* - * Copyright (c) 2013, Kevin Läufer - * Copyright (c) 2014-2018, Niklas Hauser - * Copyright (c) 2017, Sascha Schade * Copyright (c) 2020, Erik Henriksson * * This file is part of the modm project. @@ -21,16 +18,13 @@ #include -namespace modm -{ -namespace platform +namespace modm::platform { /** * Base class for the UART classes * * Provides some common enum that do not depend on the specific UART. * - * @author Kevin Laeufer * @ingroup modm_platform_uart */ class UartBase @@ -38,12 +32,10 @@ class UartBase public: enum class Parity : uint32_t { - Even = 0, - Odd = 1, - Disabled = 2, + Even = 0, + Odd = 1, + Disabled = 2, }; }; -} // namespace platform - -} // namespace modm +} // namespace modm::platform diff --git a/src/modm/platform/uart/sam/uart_hal.hpp.in b/src/modm/platform/uart/sam/uart_hal.hpp.in index 243fc2a8b3..dce1143e6b 100644 --- a/src/modm/platform/uart/sam/uart_hal.hpp.in +++ b/src/modm/platform/uart/sam/uart_hal.hpp.in @@ -1,7 +1,4 @@ /* - * Copyright (c) 2013, Sascha Schade - * Copyright (c) 2013-2014, 2016, Kevin Läufer - * Copyright (c) 2013-2017, Niklas Hauser * Copyright (c) 2020, Erik Henriksson * * This file is part of the modm project. @@ -15,28 +12,24 @@ #pragma once #include +#include #include "../device.hpp" #include "uart_base.hpp" #include "modm/platform/clock/gclk.hpp" -namespace modm -{ - -namespace platform +namespace modm::platform { /** - * Universal asynchronous receiver transmitter ({{ uart_name ~ "Hal" ~ id }}) - * - * Not available on the low- and medium density devices. + * Universal asynchronous receiver transmitter (UartHal{{ id }}) * * Very basic implementation that exposes more hardware features than * the regular Usart classes. * - * @author Kevin Laeufer + * @author Erik Henriksson * @ingroup modm_platform_uart */ -class {{ uart_name ~ "Hal" ~ id }} : public UartBase +class UartHal{{ id }} : public UartBase, /** @cond */protected modm::PeripheralDriver/** @endcond */ { private: /** @@ -68,9 +61,9 @@ public: * Enables clocks, the UART peripheral (but neither TX nor RX) * Sets baudrate and parity. */ - template< class SystemClock, baudrate_t baudrate > + template< class SystemClock, baudrate_t baudrate, percent_t tolerance=pct(1) > static void - initialize( Parity parity = Parity::Disabled); + initialize(Parity parity = Parity::Disabled); /** * \brief Write a single byte to the transmit register @@ -117,8 +110,6 @@ public: isTransmitRegisterEmpty(); }; -} // namespace platform - -} // namespace modm +} // namespace modm::platform #include "uart_hal_{{ id }}_impl.hpp" diff --git a/src/modm/platform/uart/sam/uart_hal_impl.hpp.in b/src/modm/platform/uart/sam/uart_hal_impl.hpp.in index 1fd329c722..8cfbddcb59 100644 --- a/src/modm/platform/uart/sam/uart_hal_impl.hpp.in +++ b/src/modm/platform/uart/sam/uart_hal_impl.hpp.in @@ -1,10 +1,4 @@ /* - * Copyright (c) 2013-2014, 2016, Kevin Läufer - * Copyright (c) 2013-2017, Niklas Hauser - * Copyright (c) 2017, Fabian Greif - * Copyright (c) 2017, Sascha Schade - * Copyright (c) 2018, Christopher Durand - * Copyright (c) 2018, Lucas Mösch * Copyright (c) 2020, Erik Henriksson * * This file is part of the modm project. @@ -15,13 +9,17 @@ */ // ---------------------------------------------------------------------------- -%% set name = uart_name ~ "Hal" ~ id +%% set name = "UartHal" ~ id %% set sercom = sercom_name ~ id %% set peripheral = sercom | upper +#include + +namespace modm::platform +{ // ---------------------------------------------------------------------------- void -modm::platform::{{ name }}::setParity(const Parity parity) +{{ name }}::setParity(const Parity parity) { if (parity != Parity::Disabled) { {{ peripheral }}->USART.CTRLA.bit.FORM = 0x1; // Enable parity. @@ -32,29 +30,29 @@ modm::platform::{{ name }}::setParity(const Parity parity) } void -modm::platform::{{ name }}::enable() +{{ name }}::enable() { {{ peripheral }}->USART.CTRLA.bit.ENABLE = true; // Uart Enable while({{ peripheral }}->USART.SYNCBUSY.bit.ENABLE); // Wait for sync. } void -modm::platform::{{ name }}::disable() +{{ name }}::disable() { {{ peripheral }}->USART.CTRLA.bit.ENABLE = false; // Uart Disable while({{ peripheral }}->USART.SYNCBUSY.bit.ENABLE); // Wait for sync. } void -modm::platform::{{ name }}::reset() +{{ name }}::reset() { {{ peripheral }}->USART.CTRLA.bit.SWRST = true; // Uart Reset while({{ peripheral }}->USART.SYNCBUSY.bit.SWRST); // Wait for sync. } -template -void modm_always_inline -modm::platform::{{ name }}::initialize(Parity parity) +template +void +{{ name }}::initialize(Parity parity) { // Enable peripheral clock in power manager. PM->APBCMASK.bit.{{ peripheral }}_ = true; @@ -77,65 +75,70 @@ modm::platform::{{ name }}::initialize(Parity parity) setParity(parity); // Set stop bits to 1 {{ peripheral }}->USART.CTRLB.bit.SBMODE = 0x0; - // fractional baud rate - {{ peripheral }}->USART.CTRLA.bit.SAMPR = 0x1; - // set baudrate (multiply by 8 to calc fractional part) - uint16_t baudTimes8 = (SystemClock::Frequency * 8) / (16 * baudrate); - SERCOM0->USART.BAUD.FRAC.BAUD = baudTimes8 / 8; - SERCOM0->USART.BAUD.FRAC.FP = baudTimes8 % 8; - // uint16_t baud = SystemClock::Frequency / (16 * baudrate); - // SERCOM0->USART.BAUD.reg = baud; + + // Oversampling 8x or 16x + constexpr uint32_t scalar = (baudrate * 16l > SystemClock::Frequency) ? 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); + assertBaudrateInTolerance< result.frequency, baudrate, tolerance >(); + {{ peripheral }}->USART.BAUD.FRAC.BAUD = result.prescaler >> 3; + {{ peripheral }}->USART.BAUD.FRAC.FP = result.prescaler & 0b111; + + // Enable USART setReceiverEnable(true); setTransmitterEnable(true); - // Enable USART enable(); } void -modm::platform::{{ name }}::write(uint8_t data) +{{ name }}::write(uint8_t data) { {{ peripheral }}->USART.DATA.reg = data; } void -modm::platform::{{ name }}::read(uint8_t &data) +{{ name }}::read(uint8_t &data) { data = {{ peripheral }}->USART.DATA.reg; } void -modm::platform::{{ name }}::setTransmitterEnable(const bool enable) +{{ name }}::setTransmitterEnable(const bool enable) { {{ peripheral }}->USART.CTRLB.bit.TXEN = enable; } void -modm::platform::{{ name }}::setReceiverEnable(bool enable) +{{ name }}::setReceiverEnable(bool enable) { {{ peripheral }}->USART.CTRLB.bit.RXEN = enable; } void -modm::platform::{{ name }}::enableOperation() +{{ name }}::enableOperation() { enable(); } void -modm::platform::{{ name }}::disableOperation() +{{ name }}::disableOperation() { disable(); } bool -modm::platform::{{ name }}::isReceiveRegisterNotEmpty() +{{ name }}::isReceiveRegisterNotEmpty() { return {{ peripheral }}->USART.INTFLAG.bit.RXC; } bool -modm::platform::{{ name }}::isTransmitRegisterEmpty() +{{ name }}::isTransmitRegisterEmpty() { return {{ peripheral }}->USART.INTFLAG.bit.DRE; } + +} // namespace modm::platform