I've written a sketch to set up generic clock 2 to output the 32 kHz crystal oscillator on pin PA16 (Pin eight on the MKRGSM1400). As written below, I get a 32 KHz signal on PA16 as expected. But there are some issues. When I change the clock source to (say) GCLK_GENCTRL_SRC_OSC8M (8 MHz oscillator) or GCLK_GENCTRL_SRC_DFLL48M (48 MHz DLL) I still get a 32 kHz signal. If I try a different generic clock and pin combination, such as generic clock 4 on PA10 (as per the I/O multiplexing section of the SAMD21 datasheet), I just get a high or low signal corresponding to the bit GCLK_GENCTRL_OOV (output off value) in register GENCTRL.
I can't imagine what causes this behaviour and I'm out of ideas for debugging this
void setupGenericClock(unsigned int clockGeneratorID, unsigned int divisionFactor, bool divFactorIsLogarithmic,
unsigned int oscillatorToUse, bool outputPinDefaultsHigh, bool outputPinIsEnabled,
bool outputPinClocksInStandby, unsigned int peripheralToClock, bool clockIsWriteProtected)
{
//1. Write to the GENDIV register to set the division factor
GCLK->GENDIV.reg = GCLK_GENDIV_ID(clockGeneratorID) |
GCLK_GENDIV_DIV(divisionFactor);
//2. Write to the GENCTRL register to select the oscillator source
GCLK->GENCTRL.reg = GCLK_GENCTRL_ID(clockGeneratorID) |
GCLK_GENCTRL_SRC(oscillatorToUse) |
GCLK_GENCTRL_GENEN |
GCLK_GENCTRL_IDC |
(GCLK_GENCTRL_OOV * outputPinDefaultsHigh) |
(GCLK_GENCTRL_OE * outputPinIsEnabled) |
(GCLK_GENCTRL_DIVSEL * divFactorIsLogarithmic) |
(GCLK_GENCTRL_RUNSTDBY * outputPinClocksInStandby);
//3. Write to the CLKCTRL register to enable the clock generator and point it at the peripheral
GCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID(peripheralToClock) | //datasheet is inconsistent; this is the id of the peripheral.
GCLK_CLKCTRL_GEN(clockGeneratorID) |
GCLK_CLKCTRL_CLKEN;
}
const int PA{0};
const int PB{1};
// To use pin Pxy as one of the available peripheral functions, the corresponding PMUXEN bit of the PINCFGy register must be '1'.
void configurePinForClockOutput(int port, int pinNumberOfPort) {
const int PMUX_register_number = pinNumberOfPort/2; //intentionally narrowing to an int b/c each register serves two pins (see p.433)
const int PINCFG_register_number{pinNumberOfPort};
const bool pinNumberIsOdd = pinNumberOfPort % 2;
if(pinNumberIsOdd)
{
PORT->Group[port].PMUX[PMUX_register_number].bit.PMUXO = PORT_PMUX_PMUXO_H_Val;
} else
{
PORT->Group[port].PMUX[PMUX_register_number].bit.PMUXE = PORT_PMUX_PMUXE_H_Val;
}
PORT->Group[port].PINCFG[PINCFG_register_number].bit.PMUXEN = 1;
}
int main() {
setupGenericClock(2, 1, false, GCLK_GENCTRL_SRC_XOSC32K, true, true, true, GCM_WDT, false);
configurePinForClockOutput(PA, 16);
while(1);
}
/* Clock choices:
GCLK_GENCTRL_SRC_XOSC
GCLK_GENCTRL_SRC_GCLKIN
GCLK_GENCTRL_SRC_GCLKGEN1
GCLK_GENCTRL_SRC_OSCULP32K
GCLK_GENCTRL_SRC_OSC32K
GCLK_GENCTRL_SRC_XOSC32K
GCLK_GENCTRL_SRC_OSC8M
GCLK_GENCTRL_SRC_DFLL48M
*/