Skip to content

Commit

Permalink
[uart] Add basic SAMD UART driver
Browse files Browse the repository at this point in the history
  • Loading branch information
henrikssn authored and salkinium committed Jul 8, 2020
1 parent 2ed785d commit 04688bc
Show file tree
Hide file tree
Showing 7 changed files with 622 additions and 3 deletions.
10 changes: 7 additions & 3 deletions src/modm/board/feather_m0/module.lb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#
# Copyright (c) 2016-2018, Niklas Hauser
# Copyright (c) 2017, Fabian Greif
# Copyright (c) 2020, Erik Henriksson
#
# This file is part of the modm project.
#
Expand Down Expand Up @@ -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/"
Expand Down
88 changes: 88 additions & 0 deletions src/modm/platform/uart/sam/module.lb
Original file line number Diff line number Diff line change
@@ -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")
109 changes: 109 additions & 0 deletions src/modm/platform/uart/sam/uart.cpp.in
Original file line number Diff line number Diff line change
@@ -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;
}
101 changes: 101 additions & 0 deletions src/modm/platform/uart/sam/uart.hpp.in
Original file line number Diff line number Diff line change
@@ -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 <modm/architecture/interface/uart.hpp>
#include <modm/platform/gpio/connector.hpp>
#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<Peripheral _> class RxPin, template<Peripheral _> class TxPin >
static void
connect()
{
using Connector = GpioConnector<Peripheral::{{ sercom }}, RxPin, TxPin>;
using Rx = typename Connector::template GetSignal< Gpio::Signal::Pad3 >;
using Tx = typename Connector::template GetSignal< Gpio::Signal::Pad2 >;
static_assert(Connector::template IsValid<Rx>,
"{{ name }}::connect() requires Rx on {{ sercom }}Pad3");
static_assert(Connector::template IsValid<Tx>,
"{{ 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<SystemClock, baudrate>(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
49 changes: 49 additions & 0 deletions src/modm/platform/uart/sam/uart_base.hpp.in
Original file line number Diff line number Diff line change
@@ -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 <stdint.h>
#include "../device.hpp"
#include <modm/architecture/interface/register.hpp>
#include <modm/architecture/interface/interrupt.hpp>
#include <modm/math/units.hpp>


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
Loading

0 comments on commit 04688bc

Please sign in to comment.