Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds UART support to SAM platform #430

Merged
merged 4 commits into from
Jul 8, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 1 addition & 4 deletions examples/samd/blink/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,9 @@ int
main()
{
Board::initialize();
LedRx::set();

while (1)
{
LedTx::toggle();
LedRx::toggle();
LedD13::toggle();
modm::delay(500ms);

#ifdef MODM_BOARD_HAS_LOGGER
Expand Down
2 changes: 1 addition & 1 deletion examples/samd/blink/project.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<library>
<extends>modm:samd21-mini</extends>
<extends>modm:feather-m0</extends>
<options>
<option name="modm:build:build.path">../../../build/samd/blink</option>
</options>
Expand Down
38 changes: 24 additions & 14 deletions src/modm/board/feather_m0/board.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/*
* Copyright (c) 2016-2017, Sascha Schade
* Copyright (c) 2017-2018, Niklas Hauser
* Copyright (c) 2020, Erik Henriksson
*
* This file is part of the modm project.
*
Expand All @@ -12,8 +13,10 @@

#pragma once

#include <modm/debug/logger.hpp>
#include <modm/platform.hpp>
#include <modm/architecture/interface/clock.hpp>
#define MODM_BOARD_HAS_LOGGER

using namespace modm::platform;

Expand All @@ -24,7 +27,8 @@ namespace Board
using namespace modm::literals;

/// samd21g18a running at 48MHz generated from the external 32.768 KHz crystal
struct SystemClock {
struct SystemClock
{
static constexpr uint32_t Frequency = 48_MHz;
// static constexpr uint32_t Ahb = Frequency;
// static constexpr uint32_t Apba = Frequency;
Expand All @@ -51,31 +55,37 @@ struct SystemClock {
static bool inline
enable()
{
// GenericClockController::enableExternalCrystal(Frequency);

// switch system clock to PLL output
// GenericClockController::enableSystemClock(ClockControl::SystemClockSource::Pll);

// update frequencies for busy-wait delay functions
// GenericClockController::updateCoreFrequency<Frequency>();

GenericClockController::setFlashLatency<Frequency>();
GenericClockController::initExternalCrystal();
GenericClockController::initDFLL48MHz();
GenericClockController::initOsc8MHz();
GenericClockController::setSystemClock(ClockSource::DFLL48M);
GenericClockController::updateCoreFrequency<Frequency>();
return true;
}
};

// User LED (inverted, because connected to 3V3)
// using LedRed = GpioOutputA17;
// using Leds = SoftwareGpioPort< LedRed >;

// using Button = GpioUnused;
namespace debug_logger
{
using Rx = GpioInputA11;
using Tx = GpioOutputA10;
}

using LoggerDevice = modm::IODeviceWrapper< Uart0, modm::IOBuffer::BlockIfFull >;

using LedD13 = GpioInverted<GpioOutputA17>;
// using Leds = SoftwareGpioPort< LedD13 >;

inline void
initialize()
{
SystemClock::enable();
SysTickTimer::initialize<SystemClock>();
Uart0::connect<debug_logger::Rx::Pad3, debug_logger::Tx::Pad2>();
salkinium marked this conversation as resolved.
Show resolved Hide resolved
Uart0::initialize<SystemClock, 9'600_Bd>();

// LedGreen::setOutput(modm::Gpio::Low);
LedD13::setOutput(modm::Gpio::Low);
}

} // Board namespace
1 change: 1 addition & 0 deletions src/modm/board/feather_m0/board.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

<options>
<option name="modm:target">samd21g18a-uu</option>
<option name="modm:platform:cortex-m:linkerscript.flash_offset">0x2000</option>
</options>
<modules>
<module>modm:board:feather-m0</module>
Expand Down
11 changes: 8 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 All @@ -29,13 +30,17 @@ def prepare(module, options):
if not options[":target"].partname.startswith("samd21g18a"):
return False

module.depends(":platform:gclk", ":platform:core", ":platform:clock")
module.depends(":platform:gclk", ":platform:core", ":platform:clock",
":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,
salkinium marked this conversation as resolved.
Show resolved Hide resolved
}
env.template("../board.cpp.in", "board.cpp")
env.copy('.')

# env.outbasepath = "modm/openocd/modm/board/"
Expand Down
1 change: 1 addition & 0 deletions src/modm/board/samd21_mini/board.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ initialize()
SystemClock::enable();
SysTickTimer::initialize<SystemClock>();

LedD13::setOutput(modm::Gpio::Low);
LedTx::setOutput(modm::Gpio::Low);
LedRx::setOutput(modm::Gpio::Low);
}
Expand Down
96 changes: 96 additions & 0 deletions src/modm/platform/clock/sam/gclk.cpp.in
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/*
* Copyright (c) 2013-2014, Kevin Läufer
* Copyright (c) 2014-2017, Niklas Hauser
* Copyright (c) 2020, Erik Henriksson
*
* This file is part of the modm project.
*
Expand All @@ -12,9 +13,104 @@

#include "../device.hpp"
#include "gclk.hpp"
#include "modm/math/units.hpp"

namespace modm::platform
{
uint16_t modm_fastdata delay_fcpu_MHz(1);
uint16_t modm_fastdata delay_ns_per_loop({{ loops * 1000 }});
}

bool
modm::platform::GenericClockController::initOsc8MHz(
uint32_t waitCycles)
{
SYSCTRL->OSC8M.bit.PRESC = 0x0;
SYSCTRL->OSC8M.bit.ONDEMAND = true;
SYSCTRL->OSC8M.bit.RUNSTDBY = false;
SYSCTRL->OSC8M.bit.ENABLE = true;
while (!SYSCTRL->PCLKSR.bit.OSC8MRDY && --waitCycles);
return waitCycles;
}

bool
modm::platform::GenericClockController::initExternalCrystal(
uint32_t waitCycles)
{
// Enable external crystal.
SYSCTRL->XOSC32K.reg =
SYSCTRL_XOSC32K_STARTUP( 0x6u ) |
SYSCTRL_XOSC32K_XTALEN | 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
modm::platform::GenericClockController::initDFLL48MHz(
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_GEN_GCLK1 |
GCLK_CLKCTRL_CLKEN;
// Wait for synchronization.
while (GCLK->STATUS.bit.SYNCBUSY and --waitCycles);

// Errata 1.2.1: Disable the OnDemand mode
SYSCTRL->DFLLCTRL.bit.ONDEMAND = 0;
// Wait for synchronization.
while (!SYSCTRL->PCLKSR.bit.DFLLRDY and --waitCycles);

SYSCTRL->DFLLMUL.reg =
SYSCTRL_DFLLMUL_CSTEP( 31 ) |
SYSCTRL_DFLLMUL_FSTEP( 511 ) |
SYSCTRL_DFLLMUL_MUL((48_MHz + 32'768_Hz/2) / 32'768_Hz);
// Wait for synchronization.
while (!SYSCTRL->PCLKSR.bit.DFLLRDY and --waitCycles);
// Write full configuration to DFLL control register
SYSCTRL->DFLLCTRL.reg |=
SYSCTRL_DFLLCTRL_MODE | // Enable the closed loop mode
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);
// Enable the DFLL
SYSCTRL->DFLLCTRL.bit.ENABLE = true;
// Wait for locks flags
while (
!(SYSCTRL->PCLKSR.reg & SYSCTRL_PCLKSR_DFLLLCKC) ||
!(SYSCTRL->PCLKSR.reg & SYSCTRL_PCLKSR_DFLLLCKF));
// Wait for synchronization.
while (!SYSCTRL->PCLKSR.bit.DFLLRDY and --waitCycles)
return waitCycles;
}

bool
modm::platform::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;
}
46 changes: 44 additions & 2 deletions src/modm/platform/clock/sam/gclk.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2019, Ethan Slattery
* Copyright (c) 2020, Erik Henriksson
*
* This file is part of the modm project.
*
Expand All @@ -17,6 +18,13 @@
namespace modm::platform
{

enum class
ClockSource : uint32_t
{
OSC8M = GCLK_GENCTRL_SRC_OSC8M_Val,
DFLL48M = GCLK_GENCTRL_SRC_DFLL48M_Val
};

/**
* Clock management
*
Expand All @@ -25,9 +33,43 @@ namespace modm::platform
class GenericClockController
{
public:
template< uint32_t Core_Hz >
void
template< uint32_t Core_Hz>
static uint32_t
setFlashLatency();

template< uint32_t Core_Hz >
static void
updateCoreFrequency();

static bool
initOsc8MHz(uint32_t waitCycles = 2048);

static bool
initExternalCrystal(uint32_t waitCycles = 2048);

static bool
initDFLL48MHz(uint32_t waitCycles = 2048);

static bool
setSystemClock(
ClockSource source = ClockSource::OSC8M,
uint32_t waitCycles = 2048);

private:
enum class
ClockGenerator : uint32_t
{
System = 0,
ExternalCrystal32K = 1,
ULP32K = 2,
Internal8M = 3,
};

enum class
ClockMux : uint32_t
{
DFLL48M = 0,
};
};

}
Expand Down
15 changes: 15 additions & 0 deletions src/modm/platform/clock/sam/gclk_impl.hpp.in
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2019, Ethan Slattery
* Copyright (c) 2020, Erik Henriksson
*
* This file is part of the modm project.
*
Expand All @@ -10,6 +11,7 @@
// ----------------------------------------------------------------------------

#include <cmath>
#include "modm/math/units.hpp"

namespace modm::platform
{
Expand All @@ -26,5 +28,18 @@ GenericClockController::updateCoreFrequency()
delay_ns_per_loop = ::round({{loops}}000.f / (Core_Hz / 1'000'000));
}

template< uint32_t Core_Hz >
uint32_t
GenericClockController::setFlashLatency()
{
// See table 41.11 (NVM Characteristics) in the datasheet
if (Core_Hz > 24_MHz) {
NVMCTRL->CTRLB.bit.RWS = NVMCTRL_CTRLB_RWS_HALF_Val;
} else {
NVMCTRL->CTRLB.bit.RWS = NVMCTRL_CTRLB_RWS_SINGLE_Val;
}
salkinium marked this conversation as resolved.
Show resolved Hide resolved
return Core_Hz;
}

}

Loading