Skip to content

Commit

Permalink
Basic clock configuration for SAMV devices
Browse files Browse the repository at this point in the history
  • Loading branch information
twasilczyk committed Sep 13, 2021
1 parent 9a08b11 commit 797a63f
Show file tree
Hide file tree
Showing 10 changed files with 80 additions and 56 deletions.
37 changes: 34 additions & 3 deletions examples/samv/blink/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,47 @@
#include <modm/architecture/interface/clock.hpp>
#include <modm/platform.hpp>

using namespace std::chrono_literals;
using namespace modm::platform;

struct SystemClock
{
// Chosen to achieve 120MHz system clock
static constexpr uint32_t PllAMult = 3662; // 25?

static constexpr uint32_t Frequency = PllAMult * SlowClkFreqHz;
static bool inline
enable()
{
ClockGen::setFlashLatency<Frequency>();
ClockGen::updateCoreFrequency<Frequency>();
//ClockGen::enableExternal32Khz(false);
ClockGen::enablePllA<PllAMult>();
ClockGen::selectMasterClk<MasterClkSource::MAIN_CLK, MasterClkPrescaler::CLK_1>();
return true;
}
};

int
main()
{
#if 0
WDT->WDT_MR = (WDT_MR_WDDIS_Msk); // turn off Watchdog
SystemClock::enable();
SysTickTimer::initialize<SystemClock>();

using Led0 = modm::platform::GpioD17;
using Led1 = modm::platform::GpioD16;
using Led2 = modm::platform::GpioD15;

Led0::setOutput(false);
Led1::setOutput(true);
Led2::setOutput(false);

while (1)
{
Led::toggle();
Led0::toggle();
modm::delay(500ms);
}
#endif

return 0;
}
9 changes: 9 additions & 0 deletions examples/samv/blink/openocd.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
source [find interface/jlink.cfg]
transport select swd

source [find target/atsamv.cfg]

init
halt
atsamv gpnvm set 1
resume
4 changes: 4 additions & 0 deletions examples/samv/blink/project.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,14 @@
<options>
<option name="modm:target">samv70n20b-aabt</option>
<option name="modm:build:build.path">../../../build/samv/blink</option>
<option name="modm:build:openocd.cfg">openocd.cfg</option>
</options>
<modules>
<module>modm:build:scons</module>
<module>modm:platform:core</module>
<module>modm:platform:clock</module>
<module>modm:platform:gpio</module>
<module>modm:architecture:delay</module>
<module>modm:platform:clockgen</module>
</modules>
</library>
14 changes: 3 additions & 11 deletions src/modm/platform/clock/samg/clockgen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,6 @@ uint32_t ClockGen::masterClkFrequency() {
return mainClkFrequency() / div;
case MasterClkSource::PLLA_CLK:
return pllAFrequency() / div;
case MasterClkSource::PLLB_CLK:
return pllBFrequency() / div;
default:
return 0;
}
Expand All @@ -95,18 +93,12 @@ uint32_t ClockGen::mainClkFrequency() {
uint32_t ClockGen::pllAFrequency() {
uint32_t mul = ((PMC->CKGR_PLLAR & CKGR_PLLAR_MULA_Msk) >> CKGR_PLLAR_MULA_Pos) + 1;
uint32_t freq = SlowClkFreqHz * mul;
// TODO: CKGR_PLLAR_DIVA
#if 0
if(PMC->PMC_MCKR & PMC_MCKR_PLLADIV2) {
freq /= 2;
}
return freq;
}

uint32_t ClockGen::pllBFrequency() {
uint32_t mul = ((PMC->CKGR_PLLBR & CKGR_PLLBR_MULB_Msk) >> CKGR_PLLBR_MULB_Pos) + 1;
uint32_t freq = SlowClkFreqHz * mul;
if(PMC->PMC_MCKR & PMC_MCKR_PLLBDIV2) {
freq /= 2;
}
#endif
return freq;
}

Expand Down
23 changes: 0 additions & 23 deletions src/modm/platform/clock/samg/clockgen.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ enum class MasterClkSource : uint32_t {
SLOW_CLK = PMC_MCKR_CSS_SLOW_CLK_Val,
MAIN_CLK = PMC_MCKR_CSS_MAIN_CLK_Val,
PLLA_CLK = PMC_MCKR_CSS_PLLA_CLK_Val,
PLLB_CLK = PMC_MCKR_CSS_PLLB_CLK_Val
};

enum class MasterClkPrescaler : uint32_t {
Expand All @@ -44,31 +43,15 @@ enum class MainInternalFreq : uint32_t {
};

enum class ClockPeripheral : uint32_t {
Flexcom0 = ID_FLEXCOM0,
Flexcom1 = ID_FLEXCOM1,
Flexcom2 = ID_FLEXCOM2,
Flexcom3 = ID_FLEXCOM3,
Flexcom4 = ID_FLEXCOM4,
Flexcom5 = ID_FLEXCOM5,
Flexcom6 = ID_FLEXCOM6,
Flexcom7 = ID_FLEXCOM7,
PioA = ID_PIOA,
PioB = ID_PIOB,
Pdmic0 = ID_PDMIC0,
Pdmic1 = ID_PDMIC1,
Mem2Mem = ID_MEM2MEM,
I2sc0 = ID_I2SC0,
I2sc1 = ID_I2SC1,
Tc0 = ID_TC0_CHANNEL0,
Tc1 = ID_TC0_CHANNEL1,
Tc2 = ID_TC0_CHANNEL2,
Tc3 = ID_TC1_CHANNEL0,
Tc4 = ID_TC1_CHANNEL1,
Tc5 = ID_TC1_CHANNEL2,
Adc = ID_ADC,
Uhp = ID_UHP,
Udp = ID_UDP,
Crccu = ID_CRCCU
};

static constexpr uint32_t SlowClkFreqHz = 32'768;
Expand Down Expand Up @@ -108,9 +91,6 @@ class ClockGen {
template<uint32_t multiplier>
static void enablePllA(uint32_t wait_cycles = 50);

template<uint32_t multiplier>
static void enablePllB(uint32_t wait_cycles = 50);

template <MasterClkSource src, MasterClkPrescaler pres>
static void selectMasterClk();

Expand All @@ -131,9 +111,6 @@ class ClockGen {
/** Returns the configured frequency of PLL A output */
static uint32_t pllAFrequency();

/** Returns the configured frequency of PLL B output */
static uint32_t pllBFrequency();

template< ClockPeripheral peripheral >
static void
enable();
Expand Down
15 changes: 2 additions & 13 deletions src/modm/platform/clock/samg/clockgen_impl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ template <MasterClkSource src, MasterClkPrescaler pres>
void ClockGen::selectMasterClk() {
// Datasheet says when selecting PLL as source, write PRES first, otherwise
// write CSS first.
if(src == MasterClkSource::PLLA_CLK || src == MasterClkSource::PLLB_CLK) {
if(src == MasterClkSource::PLLA_CLK) {
PMC->PMC_MCKR = (PMC->PMC_MCKR & ~PMC_MCKR_PRES_Msk) | PMC_MCKR_PRES((uint32_t)pres);
while(!(PMC->PMC_SR & PMC_SR_MCKRDY)) {}
PMC->PMC_MCKR = (PMC->PMC_MCKR & ~PMC_MCKR_CSS_Msk) | PMC_MCKR_CSS((uint32_t)src);
Expand All @@ -34,22 +34,11 @@ void ClockGen::enablePllA(uint32_t wait_cycles) {
PMC->CKGR_PLLAR =
CKGR_PLLAR_MULA(multiplier-1) |
CKGR_PLLAR_PLLACOUNT(wait_cycles) |
CKGR_PLLAR_PLLAEN(1);
CKGR_PLLAR_DIVA(1);
// Wait for lock bit
while(!(PMC->PMC_SR & PMC_SR_LOCKA)) {}
}

template<uint32_t multiplier>
void ClockGen::enablePllB(uint32_t wait_cycles) {
static_assert(multiplier > 8 && multiplier < 7502, "Valid PLL MUL range is 9-7501");
PMC->CKGR_PLLBR =
CKGR_PLLBR_MULB(multiplier-1) |
CKGR_PLLBR_PLLBCOUNT(wait_cycles) |
CKGR_PLLBR_PLLBEN(1);
// Wait for lock bit
while(!(PMC->PMC_SR & PMC_SR_LOCKB)) {}
}

template<uint32_t Core_Hz>
void ClockGen::updateCoreFrequency() {
SystemCoreClock = Core_Hz;
Expand Down
2 changes: 1 addition & 1 deletion src/modm/platform/clock/samg/module.lb
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ def init(module):
module.description = "Clock Generator (CKGR)"

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

module.depends(":cmsis:device", ":platform:clock")
Expand Down
1 change: 1 addition & 0 deletions src/modm/platform/gpio/sam/config.hpp.in
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ enum class PortName
{
A,
B,
D, // TODO: only if exists?
};

template<class _>
Expand Down
2 changes: 1 addition & 1 deletion src/modm/platform/gpio/sam/enable.cpp.in
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ void
modm_gpio_enable(void)
{

%% if target["family"] in ["g"]
%% if target["family"] in ["g", "v"]

PMC->PMC_PCER0 =
%% for port in options["enable_ports"]
Expand Down
29 changes: 25 additions & 4 deletions src/modm/platform/gpio/sam/pin.hpp.in
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ struct OneOfSignals
static constexpr bool value = ((std::is_same_v<typename Signal::signal, Signals>) | ...);
};

%% if target["family"] in ["g"]
%% if target["family"] in ["g", "v"]

template<class... PinConfigs>
struct PinMuxMixin
Expand All @@ -113,6 +113,10 @@ struct PinMuxMixin<PinConfig, PinConfigs...>
{
PIOB->PIO_ABCDSR[0] = (PIOB->PIO_ABCDSR[0] & ~(1<<PinConfig::pin)) | (bit0 << PinConfig::pin);
PIOB->PIO_ABCDSR[1] = (PIOB->PIO_ABCDSR[1] & ~(1<<PinConfig::pin)) | (bit1 << PinConfig::pin);
} else if constexpr (PinConfig::port == PortName::D)
{
PIOD->PIO_ABCDSR[0] = (PIOD->PIO_ABCDSR[0] & ~(1<<PinConfig::pin)) | (bit0 << PinConfig::pin);
PIOD->PIO_ABCDSR[1] = (PIOD->PIO_ABCDSR[1] & ~(1<<PinConfig::pin)) | (bit1 << PinConfig::pin);
}
PinMuxMixin<PinConfigs...>::set(cfg);
}
Expand Down Expand Up @@ -140,13 +144,17 @@ protected:
if constexpr (port == PortName::B) {
return (uint32_t*)((uint8_t*)PIOB + offset);
}
if constexpr (port == PortName::D) {
return (uint32_t*)((uint8_t*)PIOD + offset);
}
}

inline static constexpr void
setPortReg(size_t offset)
{
if constexpr (mask(PortName::A) != 0) { *getPortReg<PortName::A>(offset) = mask(PortName::A); }
if constexpr (mask(PortName::B) != 0) { *getPortReg<PortName::B>(offset) = mask(PortName::B); }
if constexpr (mask(PortName::D) != 0) { *getPortReg<PortName::D>(offset) = mask(PortName::D); }
}

template<PortName port>
Expand All @@ -163,6 +171,11 @@ protected:
static_assert(mask(PortName::B) != 0,
"Trying to read port which is not in the GpioSet!");
return *getPortReg<PortName::B>(offset) & mask(PortName::B);
} else if constexpr (port == PortName::D)
{
static_assert(mask(PortName::D) != 0,
"Trying to read port which is not in the GpioSet!");
return *getPortReg<PortName::D>(offset) & mask(PortName::D);
}
}

Expand Down Expand Up @@ -248,6 +261,12 @@ public:
tmp ^= mask(PortName::B);
*reg = tmp;
}
if constexpr (mask(PortName::D) != 0) {
volatile uint32_t *reg = getPortReg<PortName::D>(PIO_ODSR_OFFSET);
uint32_t tmp = *reg;
tmp ^= mask(PortName::D);
*reg = tmp;
}
}

static void
Expand Down Expand Up @@ -428,7 +447,7 @@ public:
inline static bool
read()
{
%% if target["family"] in ["g"]
%% if target["family"] in ["g", "v"]
return Base::readPortReg<PinConfig::port>(PIO_PDSR_OFFSET);
%% else
return Base::readPortReg<PinConfig::port>(PORT_IN_OFFSET);
Expand Down Expand Up @@ -491,12 +510,14 @@ struct Gpio<PinConfig>::As : public Gpio<PinConfig>
inline static void
connect()
{
%% if target["family"] in ["g"]
%% if target["family"] in ["g", "v"]
Pio* PIOBase;
if constexpr (PinConfig::port == PortName::A) {
PIOBase = PIOA;
} else {
} else if constexpr (PinConfig::port == PortName::B) {
PIOBase = PIOB;
} else {
PIOBase = PIOD;
}
PIOBase->PIO_PDR = (1<<PinConfig::pin);
Base::PinMux::set((uint32_t)PinSignal::function);
Expand Down

0 comments on commit 797a63f

Please sign in to comment.