diff --git a/src/modm/board/feather_m0/module.lb b/src/modm/board/feather_m0/module.lb index 39bf56f595..9da7d07fe1 100644 --- a/src/modm/board/feather_m0/module.lb +++ b/src/modm/board/feather_m0/module.lb @@ -3,6 +3,7 @@ # # Copyright (c) 2016-2018, Niklas Hauser # Copyright (c) 2017, Fabian Greif +# Copyright (c) 2020, Erik Henriksson # # This file is part of the modm project. # @@ -30,13 +31,16 @@ def prepare(module, options): return False module.depends(":platform:gclk", ":platform:core", ":platform:clock", - ":platform:gpio") + ":platform:gpio", ":platform:uart:0", ":debug") return True def build(env): env.outbasepath = "modm/src/modm/board" - # env.substitutions = {"board_has_logger": False} - # env.template("../board.cpp.in", "board.cpp") + env.substitutions = { + "with_logger": True, + "with_assert": False, + } + env.template("../board.cpp.in", "board.cpp") env.copy('.') # env.outbasepath = "modm/openocd/modm/board/" diff --git a/src/modm/platform/uart/sam/module.lb b/src/modm/platform/uart/sam/module.lb new file mode 100644 index 0000000000..707b7383da --- /dev/null +++ b/src/modm/platform/uart/sam/module.lb @@ -0,0 +1,88 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# +# Copyright (c) 2016-2018, Niklas Hauser +# Copyright (c) 2017, Fabian Greif +# Copyright (c) 2017, 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/. +# ----------------------------------------------------------------------------- + +props = {} + +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:uart") + return True + + def build(self, env): + 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 + 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)) + + props["instances"].append(self.instance) + + +def init(module): + module.name = ":platform:uart" + module.description = "Universal Asynchronous Receiver Transmitter (UART)" + +def prepare(module, options): + device = options[":target"] + if not (device.has_driver("sercom:*")): + return False + + module.depends( + ":architecture:atomic", + ":architecture:interrupt", + ":architecture:register", + ":architecture:uart", + ":math:algorithm", + ":cmsis:device", + ":platform:gpio") + + 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)) + + props["target"] = device.identifier + return True + +def build(env): + device = env[":target"] + + global props + env.substitutions = props + env.outbasepath = "modm/src/modm/platform/uart" + env.template("uart_base.hpp.in") diff --git a/src/modm/platform/uart/sam/uart.cpp.in b/src/modm/platform/uart/sam/uart.cpp.in new file mode 100644 index 0000000000..f50854773f --- /dev/null +++ b/src/modm/platform/uart/sam/uart.cpp.in @@ -0,0 +1,109 @@ +/* + * 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. + * + * 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_name ~ id +%% set hal = uart_name ~ "Hal" ~ id + +#include "../device.hpp" +#include "uart_hal_{{ id }}.hpp" +#include "uart_{{ id }}.hpp" + +void +modm::platform::{{ name }}::writeBlocking(uint8_t data) +{ + while(!{{ hal }}::isTransmitRegisterEmpty()); + {{ hal }}::write(data); +} + +void +modm::platform::{{ name }}::writeBlocking(const uint8_t *data, std::size_t length) +{ + while (length-- != 0) { + writeBlocking(*data++); + } +} + +void +modm::platform::{{ name }}::flushWriteBuffer() +{ + return; +} + +bool +modm::platform::{{ name }}::write(uint8_t data) +{ + if({{ hal }}::isTransmitRegisterEmpty()) { + {{ hal }}::write(data); + return true; + } else { + return false; + } +} + +std::size_t +modm::platform::{{ 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 +modm::platform::{{ name }}::isWriteFinished() +{ + return {{ hal }}::isTransmitRegisterEmpty(); +} + +std::size_t +modm::platform::{{ name }}::discardTransmitBuffer() +{ + return 0; +} + +bool +modm::platform::{{ name }}::read(uint8_t &data) +{ + if({{ hal }}::isReceiveRegisterNotEmpty()) { + {{ hal }}::read(data); + return true; + } else { + return false; + } +} + +std::size_t +modm::platform::{{ 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 +modm::platform::{{ name }}::discardReceiveBuffer() +{ + return 0; +} diff --git a/src/modm/platform/uart/sam/uart.hpp.in b/src/modm/platform/uart/sam/uart.hpp.in new file mode 100644 index 0000000000..c57bf4fea9 --- /dev/null +++ b/src/modm/platform/uart/sam/uart.hpp.in @@ -0,0 +1,101 @@ +/* + * 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. + * + * 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 = uart_name ~ "Hal" ~ id +%% set name = uart_name ~ id +%% set sercom = sercom_name ~ id + +#pragma once + +#include +#include +#include "uart_base.hpp" +#include "uart_hal_{{ id }}.hpp" + +namespace modm +{ + +namespace platform +{ + +/** + * Universal asynchronous receiver transmitter ({{ uart_name | upper ~ id }}) + * + * @author Kevin Laeufer + * @author Niklas Hauser + * @ingroup modm_platform_uart modm_platform_uart_{{id}} + */ +class {{ name }} : public UartBase, public ::modm::Uart +{ +public: + template< template class RxPin, template class TxPin > + static void + connect() + { + using Connector = GpioConnector; + using Rx = typename Connector::template GetSignal< Gpio::Signal::Pad3 >; + using Tx = typename Connector::template GetSignal< Gpio::Signal::Pad2 >; + static_assert(Connector::template IsValid, + "{{ name }}::connect() requires Rx on {{ sercom }}Pad3"); + static_assert(Connector::template IsValid, + "{{ name }}::connect() requires Tx on {{ sercom }}Pad2"); + Connector::connect(); + } + + template< class SystemClock, baudrate_t baudrate, percent_t tolerance=pct(1) > + static void modm_always_inline + 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 platform + +} // namespace modm diff --git a/src/modm/platform/uart/sam/uart_base.hpp.in b/src/modm/platform/uart/sam/uart_base.hpp.in new file mode 100644 index 0000000000..1ee1081452 --- /dev/null +++ b/src/modm/platform/uart/sam/uart_base.hpp.in @@ -0,0 +1,49 @@ +/* + * 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. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +// ---------------------------------------------------------------------------- + +#pragma once + +#include +#include "../device.hpp" +#include +#include +#include + + +namespace modm +{ +namespace 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 +{ +public: + enum class Parity : uint32_t + { + Even = 0, + Odd = 1, + Disabled = 2, + }; +}; + +} // namespace platform + +} // namespace modm diff --git a/src/modm/platform/uart/sam/uart_hal.hpp.in b/src/modm/platform/uart/sam/uart_hal.hpp.in new file mode 100644 index 0000000000..bb095f7e5c --- /dev/null +++ b/src/modm/platform/uart/sam/uart_hal.hpp.in @@ -0,0 +1,124 @@ +/* + * 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. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +// ---------------------------------------------------------------------------- + +#pragma once + +#include +#include "../device.hpp" +#include "uart_base.hpp" +#include "modm/platform/core/peripherals.hpp" + +namespace modm +{ + +namespace platform +{ + +/** + * Universal asynchronous receiver transmitter ({{ uart_name ~ "Hal" ~ id }}) + * + * Not available on the low- and medium density devices. + * + * Very basic implementation that exposes more hardware features than + * the regular Usart classes. + * + * @author Kevin Laeufer + * @ingroup modm_platform_uart + */ +class {{ uart_name ~ "Hal" ~ id }} : public UartBase +{ +private: + /** + * Disable Parity or Enable Odd/Even Parity + * + * This method assumes 8 databits + 1 parity bit + * Remember to enable the clock but not the UART peripheral + * before setting the party. + */ + static inline void + setParity(const Parity parity); + +public: + /// Enables the hw module + static inline void + enable(); + + /// Disables the hw module + static inline void + disable(); + + /// RResets the hw module + static inline void + reset(); + + /** + * Initialize Uart HAL Peripheral + * + * Enables clocks, the UART peripheral (but neither TX nor RX) + * Sets baudrate and parity. + */ + template< class SystemClock, baudrate_t baudrate > + static void + initialize( Parity parity = Parity::Disabled); + + /** + * \brief Write a single byte to the transmit register + * + * @warning This method does NOT do any sanity checks!! + * It is your responsibility to check if the register + * is empty! + */ + static inline void + write(uint8_t data); + + /** + * Saves the value of the receive register to data + * + * @warning This method does NOT do any sanity checks!! + * It is your responsibility to check if the register + * contains something useful! + */ + static inline void + read(uint8_t &data); + + /// Enable/Disable Transmitter + static inline void + setTransmitterEnable(const bool enable); + + /// Enable/Disable Receiver + static inline void + setReceiverEnable(bool enable); + + /// Set the UE (USART enable) bit + static inline void + enableOperation(); + + /// Clear the UE (USART enable) bit + static inline void + disableOperation(); + + /// Returns true if data has been received + static inline bool + isReceiveRegisterNotEmpty(); + + /// Returns true if data can be written + static inline bool + isTransmitRegisterEmpty(); +}; + +} // namespace platform + +} // namespace modm + +#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 new file mode 100644 index 0000000000..c8de01973f --- /dev/null +++ b/src/modm/platform/uart/sam/uart_hal_impl.hpp.in @@ -0,0 +1,144 @@ +/* + * 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. + * + * 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_name ~ "Hal" ~ id +%% set sercom = sercom_name ~ id +%% set peripheral = sercom | upper + +// ---------------------------------------------------------------------------- +void +modm::platform::{{ name }}::setParity(const Parity parity) +{ + if (parity != Parity::Disabled) { + {{ peripheral }}->USART.CTRLA.bit.FORM = 0x1; // Enable parity. + {{ peripheral }}->USART.CTRLB.bit.PMODE = uint32_t(parity); + } else { + {{ peripheral }}->USART.CTRLA.bit.FORM = 0x0; // Disable parity. + } +} + +void +modm::platform::{{ name }}::enable() +{ + {{ peripheral }}->USART.CTRLA.bit.ENABLE = true; // Uart Enable + while({{ peripheral }}->USART.SYNCBUSY.bit.ENABLE); // Wait for sync. +} + +void +modm::platform::{{ name }}::disable() +{ + {{ peripheral }}->USART.CTRLA.bit.ENABLE = false; // Uart Disable + while({{ peripheral }}->USART.SYNCBUSY.bit.ENABLE); // Wait for sync. +} + +void +modm::platform::{{ 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) +{ + // Enable peripheral clock in power manager. + PM->APBCMASK.bit.{{ peripheral }}_ = true; + // Init clock using GCLK0 as source. + GCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID_{{ peripheral }}_CORE | + GCLK_CLKCTRL_GEN_GCLK0 | + GCLK_CLKCTRL_CLKEN ; + while (GCLK->STATUS.bit.SYNCBUSY); + // Reset USART + reset(); + // Set clock mode internal + {{ 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 + {{ peripheral }}->USART.CTRLA.bit.DORD = 0x1; + // Set 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; + setReceiverEnable(true); + setTransmitterEnable(true); + // Enable USART + enable(); +} + + +void +modm::platform::{{ name }}::write(uint8_t data) +{ + {{ peripheral }}->USART.DATA.reg = data; +} + +void +modm::platform::{{ name }}::read(uint8_t &data) +{ + data = {{ peripheral }}->USART.DATA.reg; +} + +void +modm::platform::{{ name }}::setTransmitterEnable(const bool enable) +{ + {{ peripheral }}->USART.CTRLB.bit.TXEN = enable; +} + +void +modm::platform::{{ name }}::setReceiverEnable(bool enable) +{ + {{ peripheral }}->USART.CTRLB.bit.RXEN = enable; +} + +void +modm::platform::{{ name }}::enableOperation() +{ + enable(); +} + +void +modm::platform::{{ name }}::disableOperation() +{ + disable(); +} + +bool +modm::platform::{{ name }}::isReceiveRegisterNotEmpty() +{ + return {{ peripheral }}->USART.INTFLAG.bit.RXC; +} + +bool +modm::platform::{{ name }}::isTransmitRegisterEmpty() +{ + return {{ peripheral }}->USART.INTFLAG.bit.DRE; +}