SAMD21 Xplained pro set clock to output pin

Go To Last Post
9 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello, all!

I have an SAMD21 Xplained pro. I need to set a 3MHz clock to one of the pins on one of the connectors.

 

I have the following code, which I assembled from snippedts on these forums:

This code successfully outputs 1MHz on pin PA14 (which is not on any connector).

 

#include <asf.h>

void InitClock()
{
	GCLK_GENDIV_Type gendiv =
	{
		.bit.DIV = 1,   //Do not divide
		.bit.ID = 0,     //GCLK[0]
	};
	GCLK->GENDIV.reg = GCLK_GENDIV_ID(0) | GCLK_GENDIV_DIV(1);

	GCLK->GENCTRL.reg = GCLK_GENCTRL_ID(0) | GCLK_GENCTRL_SRC_OSC8M |
	GCLK_GENCTRL_RUNSTDBY | GCLK_GENCTRL_GENEN | GCLK_GENCTRL_OE;
	
	GCLK_CLKCTRL_Type clkctrl =
	{
		.bit.CLKEN = 1,
		.bit.GEN = GCLK_CLKCTRL_GEN_GCLK0_Val	//ID of the clock
	};
	GCLK->CLKCTRL.reg =clkctrl.reg;
	while (GCLK->STATUS.bit.SYNCBUSY);
}

void PortInit()
{
		PORT->Group[0].DIRSET.reg |=  PORT_PA14;
		PORT->Group[0].PINCFG[14].reg |= PORT_PINCFG_PMUXEN;
		PORT->Group[0].PMUX[7].bit.PMUXE = 0x7; //Attach clock to I/O
}

void main()
{
	
	InitClock();
	PortInit();
}

 

I need this to be 3 MHz, and on another pin (for example, pin PA15).

 

I have tried achieving this, by:

1. in InitClock() , witching the GCLK_GENCTRL_SRC_OSC8M to GCLK_CLKCTRL_ID_DFLL48 (48MHz, which I can divide by 16) - this doesn't work, whatever I do, the clock rate remains 1MHz.

 

2. in PortInit, switching PA14 to PA15, by substituting:

    - PORT->Group[0].DIRSET.reg |=  PORT_PA14;    ---> PORT->Group[0].DIRSET.reg |=  PORT_PA15;

    - PORT->Group[0].PINCFG[14].reg |= PORT_PINCFG_PMUXEN;   ---> PORT->Group[0].PINCFG[15].reg |= PORT_PINCFG_PMUXEN;

   This also doesn't work. The clock won't appear on pin PA15.

 

 

Can you please instruct me on how to output 3MHz clock on PA15 (or another pin)?

 

Thanks!

Last Edited: Fri. Feb 22, 2019 - 12:16 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You have two choices - use clkout like you have or set up a timer to divide your main clock and output to a pin. The choice of pins are limited.
You code toggle any pin with code, but the processor wont be doing much else.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

That board has a 12MHz crystal, so you need to divide

the clock by four.  Using a timer to toggle an output

pin, you would have to configure it to count two clocks

only.  This will toggle at 6MHz yielding a 3MHz square

wave.

 

--Mike

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks for the reply!
SW toggle is out of the question, because I need to run logic.
I'm entirely new to Atmel, could you please show me an example of how to use clkout so I have 3MHz?
Thanks!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks for the reply! Do you have an example of how to output the crystal to a pin? Also, I believe this MCU operates at 48MHz, no?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hey guys, I'm still struggling with this. Can anyone please suggest a course of action?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

    // Setup XOSC32K for external crystal oscillator 32768 Hz 
    REG_SYSCTRL_XOSC32K = SYSCTRL_XOSC32K_STARTUP(6) |	SYSCTRL_XOSC32K_XTALEN | SYSCTRL_XOSC32K_EN32K;
    REG_SYSCTRL_XOSC32K |= SYSCTRL_XOSC32K_ENABLE;
    while ((REG_SYSCTRL_PCLKSR & SYSCTRL_PCLKSR_XOSC32KRDY) == 0);

    // GCLK2 at 32768 Hz
    REG_GCLK_GENDIV = GCLK_GENDIV_ID(2) | GCLK_GENDIV_DIV(1);
    REG_GCLK_GENCTRL = GCLK_GENCTRL_GENEN | GCLK_GENCTRL_SRC_XOSC32K | GCLK_GENCTRL_ID(2);
    
    // Provide DFLL48M reference from GCLK2
    REG_GCLK_CLKCTRL = GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK2 | GCLK_CLKCTRL_ID_DFLL48;
    // Setup DFLL48M
    REG_SYSCTRL_DFLLCTRL = SYSCTRL_DFLLCTRL_ENABLE;
    while ((REG_SYSCTRL_PCLKSR & SYSCTRL_PCLKSR_DFLLRDY) == 0);
    REG_SYSCTRL_DFLLMUL = SYSCTRL_DFLLMUL_CSTEP(31) | SYSCTRL_DFLLMUL_FSTEP(511) | SYSCTRL_DFLLMUL_MUL(1464);
    REG_SYSCTRL_DFLLCTRL |= SYSCTRL_DFLLCTRL_MODE|SYSCTRL_DFLLCTRL_QLDIS;
    const uint32_t status = SYSCTRL_PCLKSR_DFLLLCKC | SYSCTRL_PCLKSR_DFLLLCKF;
    while((REG_SYSCTRL_PCLKSR & status) != status);
    while ((REG_SYSCTRL_PCLKSR & SYSCTRL_PCLKSR_DFLLRDY) == 0);	
    
    // Set wait state (1) for running the CPU at 48MHz
    REG_NVMCTRL_CTRLB = (1 << NVMCTRL_CTRLB_RWS_Pos);
    
    // Use DFLL48M for GCLK0 
    REG_GCLK_GENDIV = GCLK_GENDIV_ID(0) | GCLK_GENDIV_DIV(1);
    REG_GCLK_GENCTRL = GCLK_GENCTRL_OE | GCLK_GENCTRL_GENEN | GCLK_GENCTRL_SRC_DFLL48M | GCLK_GENCTRL_ID(0);
    
    // Output GCLK0 48 MHz on PB14
    PORT->Group[1].PMUX[14/2].reg |= PORT_PMUX_PMUXE(MUX_PB14H_GCLK_IO0);
    PORT->Group[1].PINCFG[14].reg |= PORT_PINCFG_PMUXEN;

Is a start, this sets up a 48 MHz clock (you can skip the last part which outputs this clock to PB14).

With that you can generate a 3 MHz output in lots of ways as mentioned. Here is one way

    // GCLK1 also using DFLL48M but divide by 16 for 3 MHz
    REG_GCLK_GENDIV = GCLK_GENDIV_ID(1) | GCLK_GENDIV_DIV(16);
    REG_GCLK_GENCTRL = GCLK_GENCTRL_OE | GCLK_GENCTRL_GENEN | GCLK_GENCTRL_SRC_DFLL48M | GCLK_GENCTRL_ID(1);		
    // Output GCLK1 on PA15
    PORT->Group[0].PMUX[15/2].reg |= PORT_PMUX_PMUXO(MUX_PA15H_GCLK_IO1);
    PORT->Group[0].PINCFG[15].reg |= PORT_PINCFG_PMUXEN;

To understand why you failed to get GCLK0 output to PA15 you need to study "I/O Multiplexing and Considerations". It depends on having a GCLK_IO for the pin you want to use (function H in the table). So it is not by accident I use GCLK1 for the 3 MHz (GCLK_IO[1] is a function available for PA15).

/Lars

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

That board has a 12MHz crystal

This is true but it's not connected to the SAMD21, it's used for the embedded debugger.

/Lars 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Very helpful, thank you. :)