SAMC21 - GCLK IO Help Needed

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

Hi,

 

I am currently making my first steps with the SAMC21E17A. The uC is soldered onto a custom PCB and I am using Eclipse and a Seeeduino Xiao (DAPLink) for flashing.

 

As a first step I would like to output the clock of GCLK0 on all the available pins (datasheet suggests 15, 25 and 27). With an LED and the following code I have verified, that indeed these pins are soldered correctly and working (LED lights up).

#include <samc21e17a.h>

int main() {

	REG_PORT_DIRSET0 = PORT_PA14;				/* Port Data Direction Set: output */
	REG_PORT_OUTSET0 = PORT_PA14;				/* Port Data Output Enable */

	while (1) {}
}

 

With the following code I can output the clock of GCLK0 on Pin 15 (PA14). However for the other two pins it doesn't work. The oscilloscope just measures some noise.

#include <samc21e17a.h>

int main() {

	//REG_NVMCTRL_CTRLB = NVMCTRL_CTRLB_RWS_DUAL;		/* NVM Read Wait States: 2 */

	//REG_OSCCTRL_OSC48MDIV = OSCCTRL_OSC48MDIV_DIV(0);     /* Oscillator Divider Selection: 0 */
	//while (REG_OSCCTRL_OSC48MDIV) {};

	REG_PORT_DIRSET0 = PORT_PA14;				/* Port Data Direction Set: output */
	PORT->Group[0].PINCFG[14].reg |= PORT_PINCFG_PMUXEN	/* Peripheral Multiplexer Enable */
			              |  PORT_PINCFG_DRVSTR;
	PORT->Group[0].PMUX[7].reg |= PINMUX_PA14H_GCLK_IO0;	/* Peripheral Multiplexing */

	REG_GCLK_GENCTRL0 |= GCLK_GENCTRL_IDC			/* Improve Duty Cycle: 50/50 */
                          |  GCLK_GENCTRL_OOV 			/* Output Off Value: 0 */
	                  |  GCLK_GENCTRL_OE;			/* Output Enable */
	while (REG_GCLK_SYNCBUSY & GCLK_SYNCBUSY_GENCTRL_GCLK0) {};

	while (1) {}
}

 

I can even change the clock to 48MHz by setting the corresponding divider (see commented out lines) to 0.

 

Am I missing something? Thanks for your help in advance!

 

Cheers,

JumpingJack

Attachment(s): 

This topic has a solution.
Last Edited: Sat. Jul 9, 2022 - 12:20 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

You should show the code that's not working also. One thing, the PMUX register needs a MUX value like MUX_PA14H_GCLK_IO0. Also note this register has both an even and an odd part (for PA27 you will need to set the odd).

/Lars

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

Lajon wrote:

PMUX register needs a MUX value like MUX_PA14H_GCLK_IO0

 

Thank you for your answer! If I am not mistaken PINMUX_PA14H_GCLK_IO0 is the needed variable? Here is an excerpt from the header file pio/samc21e17a.h:

#define PIN_PA14H_GCLK_IO0     _L_(14) /**< \brief GCLK signal: IO0 on PA14 mux H */
#define MUX_PA14H_GCLK_IO0     _L_(7)
#define PINMUX_PA14H_GCLK_IO0  ((PIN_PA14H_GCLK_IO0 << 16) | MUX_PA14H_GCLK_IO0)
#define PORT_PA14H_GCLK_IO0    (_UL_(1) << 14

 

 

And here is the code that doesn't work for pin 27:

#include <samc21e17a.h>

int main() {

	REG_PORT_DIRSET0 = PORT_PA28;				/* Port Data Direction Set: output */
	PORT->Group[0].PINCFG[28].reg |= PORT_PINCFG_PMUXEN	/* Peripheral Multiplexer Enable */
			              |  PORT_PINCFG_DRVSTR;
	PORT->Group[0].PMUX[7].reg |= PINMUX_PA28H_GCLK_IO0;	/* Peripheral Multiplexing */

	REG_GCLK_GENCTRL0 |= GCLK_GENCTRL_IDC			/* Improve Duty Cycle: 50/50 */
                          |  GCLK_GENCTRL_OOV 			/* Output Off Value: 0 */
	                  |  GCLK_GENCTRL_OE;			/* Output Enable */
	while (REG_GCLK_SYNCBUSY & GCLK_SYNCBUSY_GENCTRL_GCLK0) {};

	while (1) {}
}

 

Fortunately I have found the solution for this pin: Just replace

PORT->Group[0].PMUX[7].reg |= PINMUX_PA28H_GCLK_IO0;	/* Peripheral Multiplexing */

 

with

PORT->Group[0].PMUX[14].reg |= PINMUX_PA28H_GCLK_IO0;	/* Peripheral Multiplexing */

 

Mistakenly I was assuming that the argument in PMUX[arg] has to be the index of the peripheral type (GCLK IO has peripheral type H  ->  arg = 7). Now I know that it has to be the pin number divided by two.

 

 

Great, so now I can output GCLK on the even numbered pins 15 (PA14) and 27 (PA28). For the odd numbered pin 25 (PA27) this still doesn't work though:

#include <samc21e17a.h>

int main() {

	REG_PORT_DIRSET0 = PORT_PA27;				/* Port Data Direction Set: output */
	PORT->Group[0].PINCFG[27].reg |= PORT_PINCFG_PMUXEN	/* Peripheral Multiplexer Enable */
			              |  PORT_PINCFG_DRVSTR;
	PORT->Group[0].PMUX[13].reg |= PINMUX_PA27H_GCLK_IO0;	/* Peripheral Multiplexing */

	REG_GCLK_GENCTRL0 |= GCLK_GENCTRL_IDC			/* Improve Duty Cycle: 50/50 */
                          |  GCLK_GENCTRL_OOV 			/* Output Off Value: 0 */
	                  |  GCLK_GENCTRL_OE;			/* Output Enable */
	while (REG_GCLK_SYNCBUSY & GCLK_SYNCBUSY_GENCTRL_GCLK0) {};

	while (1) {}
}

 

 

EDIT: Same applies to the outputs of all the other GCLKs. With the code above output on even numbered pins works, while odd numbered pins still don't. Must be sth with the pinmuxing...

Last Edited: Sat. Jul 9, 2022 - 11:01 AM
This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Using expressions, given in the following code snipped, solved the problem once and for all:

 

#include <samc21e17a.h>

int main() {

	REG_PORT_DIRSET0 = PORT_PA27;				                          /* Port Data Direction Set: output */
	PORT->Group[0].PINCFG[PIN_PA27].reg |= PORT_PINCFG_PMUXEN	                  /* Peripheral Multiplexer Enable */
			              |  PORT_PINCFG_DRVSTR;
	PORT->Group[0].PMUX[(PIN_PA27>>1)].reg |= PORT_PMUX_PMUXO(MUX_PA27H_GCLK_IO0);    /* Peripheral Multiplexing */

	REG_GCLK_GENCTRL0 |= GCLK_GENCTRL_IDC			                          /* Improve Duty Cycle: 50/50 */
                          |  GCLK_GENCTRL_OOV 			                          /* Output Off Value: 0 */
	                  |  GCLK_GENCTRL_OE;			                          /* Output Enable */
	while (REG_GCLK_SYNCBUSY & GCLK_SYNCBUSY_GENCTRL_GCLK0) {};

	while (1) {}
}

 

Make sure to call the correct function, when applying the value "MUX_...". Call "PORT_PMUX_PMUXO()" for odd numbered pins and "PORT_PMUX_PMUXE()" for even numbered pins.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1
PORT->Group[0].PMUX[(PIN_PA27>>1)].reg |= PORT_PMUX_PMUXO(MUX_PA27H_GCLK_IO0);    /* Peripheral Multiplexing */

 

Surely we can come up with an expression that works for both odd and even numbered ports.

Maybe:

PORT->Group[0].PMUX[(PIN_PA27>>1)].reg |= MUX_PA27H_GCLK_IO0 << ((PIN_PA27 & 1)*4);    /* Peripheral Multiplexing */

// Or as a macro: (also corrected for portb/etc?)
#define SET_PMUX(pin, val) \
  PORT->Group[pin % 32].PMUX[(pin & 0x1F) >> 1].reg |= val << ((pin & 1)*4U);

 

Seems to work right, modulo some weird ways of loading constants...

 

int main() {
    8000:	b510      	push	{r4, lr}
  SET_PMUX(PIN_PA27, MUX_PA27H_GCLK_IO0);
    8002:	2382      	movs	r3, #130	; 0x82
    8004:	05db      	lsls	r3, r3, #23
    8006:	4a10      	ldr	r2, [pc, #64]	; (8048 <main+0x48>)
    8008:	5c99      	ldrb	r1, [r3, r2]
    800a:	2070      	movs	r0, #112	; 0x70
    800c:	4301      	orrs	r1, r0
    800e:	5499      	strb	r1, [r3, r2]
  SET_PMUX(PIN_PA28, 9);
    8010:	4a0e      	ldr	r2, [pc, #56]	; (804c <main+0x4c>)
    8012:	5c99      	ldrb	r1, [r3, r2]
    8014:	2409      	movs	r4, #9
    8016:	4321      	orrs	r1, r4
    8018:	5499      	strb	r1, [r3, r2]
  SET_PMUX(PIN_PA25, 0xA);
    801a:	490d      	ldr	r1, [pc, #52]	; (8050 <main+0x50>)
    801c:	5c5a      	ldrb	r2, [r3, r1]
    801e:	2460      	movs	r4, #96	; 0x60   ;;; SERIOUSLY?  WTF?  (works better with -Os instead of -Og)
    8020:	4264      	negs	r4, r4
    8022:	4322      	orrs	r2, r4
    8024:	b2d2      	uxtb	r2, r2
    8026:	545a      	strb	r2, [r3, r1]
  SET_PMUX(PIN_PA30, 0xB);
    8028:	4a0a      	ldr	r2, [pc, #40]	; (8054 <main+0x54>)
    802a:	5c99      	ldrb	r1, [r3, r2]
    802c:	240b      	movs	r4, #11
    802e:	4321      	orrs	r1, r4
    8030:	5499      	strb	r1, [r3, r2]
  SET_PMUX(PIN_PB09, 0x7);
    8032:	4909      	ldr	r1, [pc, #36]	; (8058 <main+0x58>)
    8034:	5c5a      	ldrb	r2, [r3, r1]
    8036:	4302      	orrs	r2, r0
    8038:	545a      	strb	r2, [r3, r1]
  SET_PMUX(PIN_PB10, 0x8);
    803a:	4908      	ldr	r1, [pc, #32]	; (805c <main+0x5c>)
    803c:	5c5a      	ldrb	r2, [r3, r1]
    803e:	2008      	movs	r0, #8
    8040:	4302      	orrs	r2, r0
    8042:	545a      	strb	r2, [r3, r1]
}
    8044:	2000      	movs	r0, #0
    8046:	bd10      	pop	{r4, pc}
    8048:	00000dbd 	.word	0x00000dbd
    804c:	00000e3e 	.word	0x00000e3e
    8050:	00000cbc 	.word	0x00000cbc
    8054:	00000f3f 	.word	0x00000f3f
    8058:	000004b4 	.word	0x000004b4
    805c:	00000535 	.word	0x00000535