From 797a63f9032c1e8a3f4ef820b41d733b9db17844 Mon Sep 17 00:00:00 2001 From: Tomasz Wasilczyk Date: Sun, 12 Sep 2021 14:44:39 -0700 Subject: [PATCH] Basic clock configuration for SAMV devices --- examples/samv/blink/main.cpp | 37 +++++++++++++++++-- examples/samv/blink/openocd.cfg | 9 +++++ examples/samv/blink/project.xml | 4 ++ src/modm/platform/clock/samg/clockgen.cpp | 14 ++----- src/modm/platform/clock/samg/clockgen.hpp | 23 ------------ .../platform/clock/samg/clockgen_impl.hpp | 15 +------- src/modm/platform/clock/samg/module.lb | 2 +- src/modm/platform/gpio/sam/config.hpp.in | 1 + src/modm/platform/gpio/sam/enable.cpp.in | 2 +- src/modm/platform/gpio/sam/pin.hpp.in | 29 +++++++++++++-- 10 files changed, 80 insertions(+), 56 deletions(-) create mode 100644 examples/samv/blink/openocd.cfg diff --git a/examples/samv/blink/main.cpp b/examples/samv/blink/main.cpp index 9ff38298bf..25c96fcb3a 100644 --- a/examples/samv/blink/main.cpp +++ b/examples/samv/blink/main.cpp @@ -11,16 +11,47 @@ #include #include +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(); + ClockGen::updateCoreFrequency(); + //ClockGen::enableExternal32Khz(false); + ClockGen::enablePllA(); + ClockGen::selectMasterClk(); + return true; + } +}; + int main() { -#if 0 + WDT->WDT_MR = (WDT_MR_WDDIS_Msk); // turn off Watchdog + SystemClock::enable(); + SysTickTimer::initialize(); + + 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; } diff --git a/examples/samv/blink/openocd.cfg b/examples/samv/blink/openocd.cfg new file mode 100644 index 0000000000..00d98e72e5 --- /dev/null +++ b/examples/samv/blink/openocd.cfg @@ -0,0 +1,9 @@ +source [find interface/jlink.cfg] +transport select swd + +source [find target/atsamv.cfg] + +init +halt +atsamv gpnvm set 1 +resume diff --git a/examples/samv/blink/project.xml b/examples/samv/blink/project.xml index dbd765bb4a..471cfbc581 100644 --- a/examples/samv/blink/project.xml +++ b/examples/samv/blink/project.xml @@ -2,10 +2,14 @@ + modm:build:scons modm:platform:core modm:platform:clock + modm:platform:gpio + modm:architecture:delay + modm:platform:clockgen diff --git a/src/modm/platform/clock/samg/clockgen.cpp b/src/modm/platform/clock/samg/clockgen.cpp index 0cd1020221..68ef57a3d5 100644 --- a/src/modm/platform/clock/samg/clockgen.cpp +++ b/src/modm/platform/clock/samg/clockgen.cpp @@ -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; } @@ -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; } diff --git a/src/modm/platform/clock/samg/clockgen.hpp b/src/modm/platform/clock/samg/clockgen.hpp index 7e282a4b7f..be2cda8d5c 100644 --- a/src/modm/platform/clock/samg/clockgen.hpp +++ b/src/modm/platform/clock/samg/clockgen.hpp @@ -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 { @@ -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; @@ -108,9 +91,6 @@ class ClockGen { template static void enablePllA(uint32_t wait_cycles = 50); - template - static void enablePllB(uint32_t wait_cycles = 50); - template static void selectMasterClk(); @@ -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(); diff --git a/src/modm/platform/clock/samg/clockgen_impl.hpp b/src/modm/platform/clock/samg/clockgen_impl.hpp index aa511eae16..109cb3c7e3 100644 --- a/src/modm/platform/clock/samg/clockgen_impl.hpp +++ b/src/modm/platform/clock/samg/clockgen_impl.hpp @@ -15,7 +15,7 @@ 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(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); @@ -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 -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 void ClockGen::updateCoreFrequency() { SystemCoreClock = Core_Hz; diff --git a/src/modm/platform/clock/samg/module.lb b/src/modm/platform/clock/samg/module.lb index 8ba8046ee3..6f76b6d2e9 100644 --- a/src/modm/platform/clock/samg/module.lb +++ b/src/modm/platform/clock/samg/module.lb @@ -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") diff --git a/src/modm/platform/gpio/sam/config.hpp.in b/src/modm/platform/gpio/sam/config.hpp.in index 0e4cd32505..de200a31e0 100644 --- a/src/modm/platform/gpio/sam/config.hpp.in +++ b/src/modm/platform/gpio/sam/config.hpp.in @@ -77,6 +77,7 @@ enum class PortName { A, B, + D, // TODO: only if exists? }; template diff --git a/src/modm/platform/gpio/sam/enable.cpp.in b/src/modm/platform/gpio/sam/enable.cpp.in index 5ddf333994..0b9c7130fd 100644 --- a/src/modm/platform/gpio/sam/enable.cpp.in +++ b/src/modm/platform/gpio/sam/enable.cpp.in @@ -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"] diff --git a/src/modm/platform/gpio/sam/pin.hpp.in b/src/modm/platform/gpio/sam/pin.hpp.in index e988fa11da..8d63084852 100644 --- a/src/modm/platform/gpio/sam/pin.hpp.in +++ b/src/modm/platform/gpio/sam/pin.hpp.in @@ -89,7 +89,7 @@ struct OneOfSignals static constexpr bool value = ((std::is_same_v) | ...); }; -%% if target["family"] in ["g"] +%% if target["family"] in ["g", "v"] template struct PinMuxMixin @@ -113,6 +113,10 @@ struct PinMuxMixin { PIOB->PIO_ABCDSR[0] = (PIOB->PIO_ABCDSR[0] & ~(1<PIO_ABCDSR[1] = (PIOB->PIO_ABCDSR[1] & ~(1<PIO_ABCDSR[0] = (PIOD->PIO_ABCDSR[0] & ~(1<PIO_ABCDSR[1] = (PIOD->PIO_ABCDSR[1] & ~(1<::set(cfg); } @@ -140,6 +144,9 @@ 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 @@ -147,6 +154,7 @@ protected: { if constexpr (mask(PortName::A) != 0) { *getPortReg(offset) = mask(PortName::A); } if constexpr (mask(PortName::B) != 0) { *getPortReg(offset) = mask(PortName::B); } + if constexpr (mask(PortName::D) != 0) { *getPortReg(offset) = mask(PortName::D); } } template @@ -163,6 +171,11 @@ protected: static_assert(mask(PortName::B) != 0, "Trying to read port which is not in the GpioSet!"); return *getPortReg(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(offset) & mask(PortName::D); } } @@ -248,6 +261,12 @@ public: tmp ^= mask(PortName::B); *reg = tmp; } + if constexpr (mask(PortName::D) != 0) { + volatile uint32_t *reg = getPortReg(PIO_ODSR_OFFSET); + uint32_t tmp = *reg; + tmp ^= mask(PortName::D); + *reg = tmp; + } } static void @@ -428,7 +447,7 @@ public: inline static bool read() { -%% if target["family"] in ["g"] +%% if target["family"] in ["g", "v"] return Base::readPortReg(PIO_PDSR_OFFSET); %% else return Base::readPortReg(PORT_IN_OFFSET); @@ -491,12 +510,14 @@ struct Gpio::As : public Gpio 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<