Skip to content

Commit

Permalink
Implement basic clock support for SAMV
Browse files Browse the repository at this point in the history
  • Loading branch information
twasilczyk committed Sep 15, 2021
1 parent c6d753c commit 2d9e176
Show file tree
Hide file tree
Showing 4 changed files with 74 additions and 19 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand All @@ -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;
Expand All @@ -109,7 +117,7 @@ uint32_t ClockGen::pllBFrequency() {
}
return freq;
}

%% endif

void ClockGen::setMainInternalFreq(MainInternalFreq freq) {
PMC->CKGR_MOR =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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;
Expand Down Expand Up @@ -108,8 +116,15 @@ class ClockGen {
template<uint32_t multiplier>
static void enablePllA(uint32_t wait_cycles = 50);

%% if target["family"] in ["g"]
template<uint32_t multiplier>
static void enablePllB(uint32_t wait_cycles = 50);
%% endif

%% if target["family"] in ["v"]
template<uint32_t multiplier>
static void enableUPll(uint32_t wait_cycles = 50);
%% endif

template <MasterClkSource src, MasterClkPrescaler pres>
static void selectMasterClk();
Expand All @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,14 @@ 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 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);
Expand All @@ -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<uint32_t multiplier>
void ClockGen::enablePllB(uint32_t wait_cycles) {
static_assert(multiplier > 8 && multiplier < 7502, "Valid PLL MUL range is 9-7501");
Expand All @@ -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<uint32_t multiplier>
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<uint32_t Core_Hz>
void ClockGen::updateCoreFrequency() {
Expand Down
12 changes: 8 additions & 4 deletions src/modm/platform/clock/sam_pmc/module.lb
Original file line number Diff line number Diff line change
Expand Up @@ -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")

0 comments on commit 2d9e176

Please sign in to comment.