Skip to content

Commit

Permalink
Add UART driver for SAMG
Browse files Browse the repository at this point in the history
  • Loading branch information
mcbridejc authored and salkinium committed Oct 22, 2021
1 parent 4dec359 commit 6e9f000
Show file tree
Hide file tree
Showing 9 changed files with 416 additions and 3 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -437,7 +437,7 @@ Please [discover modm's peripheral drivers for your specific device][discover].
<td align="center">✅</td>
<td align="center">✅</td>
<td align="center">✅</td>
<td align="center"></td>
<td align="center"></td>
<td align="center">○</td>
<td align="center">✅</td>
<td align="center">✅</td>
Expand Down
33 changes: 33 additions & 0 deletions examples/samg55_xplained_pro/uart/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* 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 <modm/board.hpp>
#include <modm/io/iostream.hpp>

using namespace modm::platform;
using namespace modm::literals;

// Create IO wrapper for the debug UART, which is connected to the built-in
// USB debugger virtual COM port
modm::IODeviceWrapper<Board::DebugUart, modm::IOBuffer::BlockIfFull> debugDevice;
modm::IOStream debugStream(debugDevice);

int
main()
{
Board::initialize();

uint32_t cycle = 0;
while (true)
{
modm::delay(1s);
debugStream.printf("Cycle: %lu\r\n", cycle);
}
}
9 changes: 9 additions & 0 deletions examples/samg55_xplained_pro/uart/project.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<library>
<extends>modm:samg55-xplained-pro</extends>
<options>
<option name="modm:build:build.path">../../../build/samg55_xplained_pro/uart</option>
</options>
<modules>
<module>modm:build:scons</module>
</modules>
</library>
10 changes: 9 additions & 1 deletion src/modm/board/samg55_xplained_pro/board.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,10 @@ struct SystemClock
// Chosen to achieve 48MHz USB clock
static constexpr uint32_t PllBMult = 1465;

static constexpr uint32_t Frequency = PllAMult * SlowClkFreqHz;
static constexpr uint32_t Frequency = PllAMult * SlowClkFreqHz; // CPU core frequency
static constexpr uint32_t Usb = PllBMult * SlowClkFreqHz;
static constexpr uint32_t Mck = Frequency; // Master clock, used by most peripherals

static bool inline
enable()
{
Expand All @@ -50,6 +52,9 @@ struct SystemClock

using Led = GpioA6;
using Button = GpioA2;
using DebugUart = Uart7;
using TxPin = GpioA28;
using RxPin = GpioA27;

inline void
initialize()
Expand All @@ -60,6 +65,9 @@ initialize()
SystemClock::enable();
SysTickTimer::initialize<SystemClock>();

DebugUart::initialize<SystemClock, 115200>();
DebugUart::connect<TxPin::Tx, RxPin::Rx>();

Led::setOutput(modm::Gpio::Low);

Button::setInput();
Expand Down
8 changes: 7 additions & 1 deletion src/modm/board/samg55_xplained_pro/module.lb
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,13 @@ def prepare(module, options):
if not options[":target"].partname == "samg55j19a-au":
return False

module.depends(":platform:clockgen", ":platform:gpio", ":platform:core", ":platform:usb");
module.depends(
":platform:clockgen",
":platform:uart:7",
":platform:gpio",
":platform:core",
":platform:usb",
":io")
return True

def build(env):
Expand Down
83 changes: 83 additions & 0 deletions src/modm/platform/uart/samg/module.lb
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
#!/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/.
# -----------------------------------------------------------------------------

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")

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):
device = env[":target"].identifier
global props
props["id"] = self.instance

env.substitutions = props
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))


def init(module):
module.name = ":platform:uart"
module.description = "Universal Synchronous Asynchronous Receiver Transmitter (UART)"

def prepare(module, options):
device = options[":target"]
if not (device.has_driver("usart:samg*")):
return False

module.depends(
":architecture:uart",
":math:algorithm",
":cmsis:device",
":platform:gpio",
":platform:clockgen")

global props
drivers = options[":target"].get_all_drivers("usart")
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.outbasepath = "modm/src/modm/platform/uart"
env.copy("uart_base.hpp")
127 changes: 127 additions & 0 deletions src/modm/platform/uart/samg/uart.cpp.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
/*
* 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 <modm/architecture/driver/atomic/queue.hpp>

namespace
{
static modm::atomic::Queue<uint8_t, {{ options["buffer.rx"] }}> rxBuffer;
static modm::atomic::Queue<uint8_t, {{ options["buffer.tx"] }}> 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
Loading

0 comments on commit 6e9f000

Please sign in to comment.