From 2d9e1768e592e600589afa9e59cd11c4a177e925 Mon Sep 17 00:00:00 2001 From: Tomasz Wasilczyk Date: Mon, 13 Sep 2021 12:02:11 -0700 Subject: [PATCH] Implement basic clock support for SAMV --- .../sam_pmc/{clockgen.cpp => clockgen.cpp.in} | 10 ++++- .../sam_pmc/{clockgen.hpp => clockgen.hpp.in} | 43 +++++++++++++------ ...clockgen_impl.hpp => clockgen_impl.hpp.in} | 28 +++++++++++- src/modm/platform/clock/sam_pmc/module.lb | 12 ++++-- 4 files changed, 74 insertions(+), 19 deletions(-) rename src/modm/platform/clock/sam_pmc/{clockgen.cpp => clockgen.cpp.in} (92%) rename src/modm/platform/clock/sam_pmc/{clockgen.hpp => clockgen.hpp.in} (89%) rename src/modm/platform/clock/sam_pmc/{clockgen_impl.hpp => clockgen_impl.hpp.in} (78%) diff --git a/src/modm/platform/clock/sam_pmc/clockgen.cpp b/src/modm/platform/clock/sam_pmc/clockgen.cpp.in similarity index 92% rename from src/modm/platform/clock/sam_pmc/clockgen.cpp rename to src/modm/platform/clock/sam_pmc/clockgen.cpp.in index 0cd1020221..8f1c031a28 100644 --- a/src/modm/platform/clock/sam_pmc/clockgen.cpp +++ b/src/modm/platform/clock/sam_pmc/clockgen.cpp.in @@ -69,8 +69,10 @@ uint32_t ClockGen::masterClkFrequency() { return mainClkFrequency() / div; case MasterClkSource::PLLA_CLK: return pllAFrequency() / div; +%% if target["family"] in ["g"] case MasterClkSource::PLLB_CLK: return pllBFrequency() / div; +%% endif default: return 0; } @@ -95,12 +97,18 @@ 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; +%% if target["family"] in ["g"] if(PMC->PMC_MCKR & PMC_MCKR_PLLADIV2) { freq /= 2; } +%% elif target["family"] in ["v"] + // division by zero error if PLLA is not enabled + freq /= ((PMC->CKGR_PLLAR & CKGR_PLLAR_DIVA_Msk) >> CKGR_PLLAR_DIVA_Pos); +%% endif return freq; } +%% if target["family"] in ["g"] uint32_t ClockGen::pllBFrequency() { uint32_t mul = ((PMC->CKGR_PLLBR & CKGR_PLLBR_MULB_Msk) >> CKGR_PLLBR_MULB_Pos) + 1; uint32_t freq = SlowClkFreqHz * mul; @@ -109,7 +117,7 @@ uint32_t ClockGen::pllBFrequency() { } return freq; } - +%% endif void ClockGen::setMainInternalFreq(MainInternalFreq freq) { PMC->CKGR_MOR = diff --git a/src/modm/platform/clock/sam_pmc/clockgen.hpp b/src/modm/platform/clock/sam_pmc/clockgen.hpp.in similarity index 89% rename from src/modm/platform/clock/sam_pmc/clockgen.hpp rename to src/modm/platform/clock/sam_pmc/clockgen.hpp.in index 7e282a4b7f..596d2ccc10 100644 --- a/src/modm/platform/clock/sam_pmc/clockgen.hpp +++ b/src/modm/platform/clock/sam_pmc/clockgen.hpp.in @@ -23,7 +23,9 @@ 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 +%% if target["family"] in ["g"] + PLLB_CLK = PMC_MCKR_CSS_PLLB_CLK_Val, +%% endif }; enum class MasterClkPrescaler : uint32_t { @@ -44,31 +46,37 @@ 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, +#if defined(ID_I2SC1) I2sc1 = ID_I2SC1, +#endif Tc0 = ID_TC0_CHANNEL0, Tc1 = ID_TC0_CHANNEL1, Tc2 = ID_TC0_CHANNEL2, Tc3 = ID_TC1_CHANNEL0, Tc4 = ID_TC1_CHANNEL1, Tc5 = ID_TC1_CHANNEL2, +%% if target["family"] in ["g"] + Pdmic0 = ID_PDMIC0, + Pdmic1 = ID_PDMIC1, + Mem2Mem = ID_MEM2MEM, Adc = ID_ADC, Uhp = ID_UHP, Udp = ID_UDP, - Crccu = ID_CRCCU + Crccu = ID_CRCCU, + Flexcom0 = ID_FLEXCOM0, + Flexcom1 = ID_FLEXCOM1, + Flexcom2 = ID_FLEXCOM2, + Flexcom3 = ID_FLEXCOM3, + Flexcom4 = ID_FLEXCOM4, + Flexcom5 = ID_FLEXCOM5, + Flexcom6 = ID_FLEXCOM6, + Flexcom7 = ID_FLEXCOM7, +%% elif target["family"] in ["v"] + // TODO: fill in SAMV clock peripherals +%% endif }; static constexpr uint32_t SlowClkFreqHz = 32'768; @@ -108,8 +116,15 @@ class ClockGen { template static void enablePllA(uint32_t wait_cycles = 50); +%% if target["family"] in ["g"] template static void enablePllB(uint32_t wait_cycles = 50); +%% endif + +%% if target["family"] in ["v"] + template + static void enableUPll(uint32_t wait_cycles = 50); +%% endif template static void selectMasterClk(); @@ -131,8 +146,10 @@ class ClockGen { /** Returns the configured frequency of PLL A output */ static uint32_t pllAFrequency(); +%% if target["family"] in ["g"] /** Returns the configured frequency of PLL B output */ static uint32_t pllBFrequency(); +%% endif template< ClockPeripheral peripheral > static void diff --git a/src/modm/platform/clock/sam_pmc/clockgen_impl.hpp b/src/modm/platform/clock/sam_pmc/clockgen_impl.hpp.in similarity index 78% rename from src/modm/platform/clock/sam_pmc/clockgen_impl.hpp rename to src/modm/platform/clock/sam_pmc/clockgen_impl.hpp.in index aa511eae16..e20971478a 100644 --- a/src/modm/platform/clock/sam_pmc/clockgen_impl.hpp +++ b/src/modm/platform/clock/sam_pmc/clockgen_impl.hpp.in @@ -15,7 +15,14 @@ template 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 target["family"] in ["g"] + constexpr bool isPll = (src == MasterClkSource::PLLA_CLK + || src == MasterClkSource::PLLB_CLK); +%% elif target["family"] in ["v"] + constexpr bool isPll = (src == MasterClkSource::PLLA_CLK); +%% endif + + if constexpr (isPll) { 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); @@ -34,11 +41,16 @@ void ClockGen::enablePllA(uint32_t wait_cycles) { PMC->CKGR_PLLAR = CKGR_PLLAR_MULA(multiplier-1) | CKGR_PLLAR_PLLACOUNT(wait_cycles) | +%% if target["family"] in ["g"] CKGR_PLLAR_PLLAEN(1); +%% elif target["family"] in ["v"] + CKGR_PLLAR_DIVA(1); +%% endif // Wait for lock bit while(!(PMC->PMC_SR & PMC_SR_LOCKA)) {} } +%% if target["family"] in ["g"] template void ClockGen::enablePllB(uint32_t wait_cycles) { static_assert(multiplier > 8 && multiplier < 7502, "Valid PLL MUL range is 9-7501"); @@ -49,6 +61,20 @@ void ClockGen::enablePllB(uint32_t wait_cycles) { // Wait for lock bit while(!(PMC->PMC_SR & PMC_SR_LOCKB)) {} } +%% endif + +%% if target["family"] in ["v"] +template +void ClockGen::enableUPll(uint32_t wait_cycles) { + static_assert(multiplier == 40 || multiplier == 30, "Valid PLL MUL values are 30 or 40"); + REG_UTMI_CKTRIM = (multiplier == 30) ? UTMI_CKTRIM_FREQ_XTAL16 : UTMI_CKTRIM_FREQ_XTAL12; + PMC->CKGR_UCKR = + CKGR_UCKR_UPLLCOUNT(wait_cycles) | + CKGR_UCKR_UPLLEN; + // Wait for lock bit + while(!(PMC->PMC_SR & PMC_SR_LOCKU)) {} +} +%% endif template void ClockGen::updateCoreFrequency() { diff --git a/src/modm/platform/clock/sam_pmc/module.lb b/src/modm/platform/clock/sam_pmc/module.lb index 8ba8046ee3..9268baa3cc 100644 --- a/src/modm/platform/clock/sam_pmc/module.lb +++ b/src/modm/platform/clock/sam_pmc/module.lb @@ -15,16 +15,20 @@ 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:samg*") + or options[":target"].has_driver("pmc:sam")): return False module.depends(":cmsis:device", ":platform:clock") return True def build(env): + bprops = {} device = env[":target"] + bprops["target"] = device.identifier + env.substitutions = bprops env.outbasepath = "modm/src/modm/platform/clock" - env.copy("clockgen.hpp") - env.copy("clockgen_impl.hpp") - env.copy("clockgen.cpp") + env.template("clockgen.hpp.in") + env.template("clockgen_impl.hpp.in") + env.template("clockgen.cpp.in")