Problem enabling clock to SERCOMx (Atmel Toolchain)

Discussions around product based on ARM Cortex M0+ core.

Moderator: nferre

hobbss
Posts: 9
Joined: Tue Jun 18, 2013 9:47 pm

Problem enabling clock to SERCOMx (Atmel Toolchain)

Tue Apr 22, 2014 10:11 pm

New ARM programmer here. Apologies if the following question is dumb...

My hardware is: SAMD20J18, on a SAMD20XPLAINED board.

My software is: Atmel Toolchain (arm-gcc)


I am trying to set up SERCOM3 as an UART.

I have the following code:

Code: Select all

	//Elsewhere
        #define PX24 (1 << 24)

	//Set up TX pin to be output
	PORT->Group[0].DIRSET.reg = PX24;
	PORT->Group[0].OUTSET.reg = PX24;
	
	//Set up mux to enable UART
	PORT->Group[0].PINCFG[24].bit.PMUXEN = 1;
	PORT->Group[0].PMUX[12].bit.PMUXE = 0x02;
	
	//Enable UART Clock
	PM->APBCMASK.bit.SERCOM3 = 1;
Everything is fine except the final line -- enabling the clock to the peripheral. I get an error: "expected identifier before '(' token"

If I do something like:

PM->APBCMASK.reg |= (1 << 5);

it compiles fine. Shouldn't the two statements do the same thing? What is wrong with the earlier statement?

Edit: Apparently I am not the only person having this issue. Looking at the code in this post:

discussions/viewtopic.php/f,31/t,22481.html, it looks like he has both lines as well (with the *.bit.SERCOMx = 1 line commented out).
hobbss
Posts: 9
Joined: Tue Jun 18, 2013 9:47 pm

Re: Problem enabling clock to SERCOMx (Atmel Toolchain)

Thu Apr 24, 2014 10:58 pm

Thanks for the tip. I will look into that. In the interest of actually printing, "Hello world" in a terminal window, I am temporarily shelving that, and just trying to get the SERCOM/USART working. Again, I am working with a SAMD20 Xplained board. This means that I cannot easily probe the USART lines, as they go through the EDBG chip, and are only available on the USB port (my probes are not reliable enough to get good contact on the IC pins).

My code is:

Code: Select all

void SystemInit(void)
{
	asm volatile("cpsie i");			//Enable Interrupts
	//SYSCTRL->OSC8M.bit.PRESC = 0x00;	//Disable Prescaler (8MHz)
	SYSCTRL->OSC8M.reg |= SYSCTRL_OSC8M_PRESC(0);
	SystemCoreClock = __SYSTEM_CLOCK;	//Configure for 8MHz operation after reset
}

void uartSetup(uint32_t baud) {
	uint64_t br;
	
	br = (uint64_t)65536 * (F_CPU - 16 * baud) / F_CPU;
	
	//Set up TX pin to be output
	PORT->Group[0].DIRSET.reg = PX24;
	PORT->Group[0].OUTSET.reg = PX24;
	
	//Set up mux to enable UART
	PORT->Group[0].PINCFG[24].reg |= PORT_PINCFG_PMUXEN;
	PORT->Group[0].PMUX[12].reg |= PORT_PMUX_PMUXE(2);
	
	//Configure global clock for SERCOM3
	GCLK->CLKCTRL.reg = (GCLK_CLKCTRL_ID(SERCOM3_GCLK_ID_CORE) | GCLK_CLKCTRL_GEN(0) | GCLK_CLKCTRL_CLKEN);
	
	//Enable Peripheral clock
	//PM->APBCMASK.bit.SERCOM3 = 1;
	PM->APBCMASK.reg |= PM_APBCMASK_SERCOM3;
	
	//Make sure UART registers are done synchronizing
//	while(SERCOM3->USART.STATUS.bit.SYNCBUSY);
	while(SERCOM3->USART.STATUS.reg & SERCOM_USART_STATUS_SYNCBUSY);
	//LSB first, SERCOM3/PAD[3]=Rx, SERCOM3/PAD[2]=Tx, Interal clock, No Parity
	SERCOM3->USART.CTRLA.reg = (SERCOM_USART_CTRLA_DORD | SERCOM_USART_CTRLA_RXPO(3) | SERCOM_USART_CTRLA_TXPO |
								 SERCOM_USART_CTRLA_MODE(SERCOM_USART_CTRLA_MODE_USART_INT_CLK));
	
	//Make sure UART registers are done synchronizing
	while(SERCOM3->USART.STATUS.reg & SERCOM_USART_STATUS_SYNCBUSY);
	//Enable Rx and Tx, and set Char size to 8 bits	(+ 1 stop bit)
	SERCOM3->USART.CTRLB.reg = (SERCOM_USART_CTRLB_RXEN | SERCOM_USART_CTRLB_TXEN | SERCOM_USART_CTRLB_CHSIZE(8));

	//Make sure UART registers are done synchronizing
	while(SERCOM3->USART.STATUS.reg & SERCOM_USART_STATUS_SYNCBUSY);
	SERCOM3->USART.BAUD.reg = (uint16_t)br;
	
	//Make sure UART registers are done synchronizing
	while(SERCOM3->USART.STATUS.reg & SERCOM_USART_STATUS_SYNCBUSY);
	SERCOM3->USART.CTRLA.reg |= SERCOM_USART_CTRLA_ENABLE;
	
	while(SERCOM3->USART.STATUS.reg & SERCOM_USART_STATUS_SYNCBUSY);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void uart3_putc(char c) {
	while(!(SERCOM3->USART.INTFLAG.reg & SERCOM_USART_INTFLAG_DRE));
	SERCOM3->USART.DATA.reg = c;	
	if(c == '\n') {
		uart3_putc('\r');
	}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void uart3_puts(char *s) {
	//String must be null terminated!!
	while(*s) {
		uart3_putc(*s);
		s++;	
	}
}

int main(void)
{
    /* Initialize the SAM system */
    SystemInit();
	
	uartSetup(115200);
	portSetup();
	
	uart3_putc('a');
	
	uart3_puts("hello world!\n");

	PORT->Group[0].OUTCLR.reg = PX24;

    while (1) 
    {
        //TODO:: Please write your application code 
    }
}
The orange user LED turns on (the last line before the While loop), so I know the code is not getting hung anywhere. However, I cannot get anything to actually print out on my terminal window. When I load some demo code (same baud rate) in, everything works, so I know there is no issue w/ the terminal software itself.

Is there any obvious step that I am missing in setting up the USART?
M14
Posts: 20
Joined: Thu Mar 27, 2014 10:51 am

Re: Problem enabling clock to SERCOMx (Atmel Toolchain)

Fri Apr 25, 2014 10:34 am

hobbss wrote:New ARM programmer here. Apologies if the following question is dumb...

My hardware is: SAMD20J18, on a SAMD20XPLAINED board.

My software is: Atmel Toolchain (arm-gcc)


I am trying to set up SERCOM3 as an UART.

I have the following code:

Code: Select all

	//Elsewhere
        #define PX24 (1 << 24)

	//Set up TX pin to be output
	PORT->Group[0].DIRSET.reg = PX24;
	PORT->Group[0].OUTSET.reg = PX24;
	
	//Set up mux to enable UART
	PORT->Group[0].PINCFG[24].bit.PMUXEN = 1;
	PORT->Group[0].PMUX[12].bit.PMUXE = 0x02;
	
	//Enable UART Clock
	PM->APBCMASK.bit.SERCOM3 = 1;
Everything is fine except the final line -- enabling the clock to the peripheral. I get an error: "expected identifier before '(' token"

If I do something like:

PM->APBCMASK.reg |= (1 << 5);

it compiles fine. Shouldn't the two statements do the same thing? What is wrong with the earlier statement?

Edit: Apparently I am not the only person having this issue. Looking at the code in this post:

discussions/viewtopic.php/f,31/t,22481.html, it looks like he has both lines as well (with the *.bit.SERCOMx = 1 line commented out).

I reported this as bug a little while ago:
http://asf.atmel.com/bugzilla/show_bug.cgi?id=3389


About the initialization, I think you should check the SERCOM registers by setting a breakpoint when the initialization is done: Debug - Windows - I/O View and click the SERCOMn module as uart.

For some reason, not all defines (like SERCOM_USART_CTRLA_DORD) do exist in my install of Atmel Studio.

Code: Select all

SERCOM3->USART.CTRLA.reg = (SERCOM_USART_CTRLA_DORD | SERCOM_USART_CTRLA_RXPO(3) | SERCOM_USART_CTRLA_TXPO |
								 SERCOM_USART_CTRLA_MODE(SERCOM_USART_CTRLA_MODE_USART_INT_CLK));
I have to mention I am using AS6.1 while AS6.2 is installed. When only AS6.1 is installed, several pretty useful SAMD20 peripheral defines are different of missing. Therefor I think it can be very useful to check if all register settings are set as they should be set.


Finally, I think the CTRLB register is set wrong:

Code: Select all

SERCOM3->USART.CTRLB.reg = (SERCOM_USART_CTRLB_RXEN | SERCOM_USART_CTRLB_TXEN | SERCOM_USART_CTRLB_CHSIZE(8));
SAM-D20 spec:
CHSIZE[2:0] Description
0x0 8 bits
0x1 9 bits
0x2-0x4 Reserved
0x5 5 bits
0x6 6 bits
0x7 7 bits

CHSIZE should be '0' to set 8bit character size.
hobbss
Posts: 9
Joined: Tue Jun 18, 2013 9:47 pm

Re: Problem enabling clock to SERCOMx (Atmel Toolchain)

Fri Apr 25, 2014 1:57 pm

Thank you for the detailed response.

Regarding the first issue, it's actually good to know that it is an actual bug rather than me doing something dumb.

Good catch regarding CTRLB. Unfortunately, even when I change it to

Code: Select all

SERCOM3->USART.CTRLB.reg = (SERCOM_USART_CTRLB_RXEN | SERCOM_USART_CTRLB_TXEN | SERCOM_USART_CTRLB_CHSIZE(0));
I am still not getting any data transmitted. I will try to examine the registers to make sure that they are being set correctly. I am using Atmel Studio 6.1, Service Pack 2 -- Version 6.1.2730. I will try to see if using 6.2 makes any difference.
hobbss
Posts: 9
Joined: Tue Jun 18, 2013 9:47 pm

Re: Problem enabling clock to SERCOMx (Atmel Toolchain)

Fri Apr 25, 2014 9:29 pm

Just a follow up (I hate stumbling across old threads where the solution is never posted).

The problem (aside from those identified above) had to do with how I was configuring my clock, not the UART module itself. Turns out, it's a bad idea to try to "OR" in a few zeros, when the default values for those bits after a reset is "1".

i.e.,

Code: Select all

void SystemInit(void)
{
	asm volatile("cpsie i");			//Enable Interrupts
	//SYSCTRL->OSC8M.bit.PRESC = 0x00;	//Disable Prescaler (8MHz)
	SYSCTRL->OSC8M.reg = (SYSCTRL->OSC8M.reg & ~SYSCTRL_OSC8M_PRESC_Msk) | SYSCTRL_OSC8M_PRESC(0);
	SystemCoreClock = __SYSTEM_CLOCK;	//Configure for 8MHz operation after reset
}
Works for disabling the prescaler on the 8MHz oscillator, while the code at the top of the thread most definitely does NOT. :oops:

Return to “SAM D20 Cortex-M0+ MCU”

Who is online

Users browsing this forum: No registered users and 1 guest