problems with UART on SAMD21 - Page 1
Forum section: electronics / general

author: DavedenHaan
author_rank: Contributor
timestamp: November 17, 2020, 10:17:09 am
content: Hello,For a project I'm currently working with the SAMD21J18A and I'm for this it is necessary to send DATA over USART.This for both debugging and application purposes.I configured the UART according to the SAMD21 datasheet.The pin on which I have a data analyzer connected are PB30 for TX and PB31 for RX which have the SERCOM 5 on D.The issue is that I'm not getting the message on the data analyzer that I'm trying to send over UART communication.Pin InitializationCode:HAL_GPIO_PIN(UART_TX,B,30)HAL_GPIO_PIN(UART_RX,B,31)USART InitializationCode:static void uart_init2(uint32_t baud){uint64_t baudrate = (uint64_t)65536 * (8000000 - 16 * baud) / 8000000;HAL_GPIO_UART_TX_out();HAL_GPIO_UART_TX_pmuxen(PORT_PMUX_PMUXE_D_Val);HAL_GPIO_UART_RX_in();HAL_GPIO_UART_RX_pmuxen(PORT_PMUX_PMUXE_D_Val);PM->APBCMASK.reg |= PM_APBCMASK_SERCOM5;GCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID(SERCOM5_GCLK_ID_CORE) |GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN(0);SERCOM5->USART.CTRLA.reg =SERCOM_USART_CTRLA_DORD | SERCOM_USART_CTRLA_MODE_USART_INT_CLK |SERCOM_USART_CTRLA_RXPO(0x1) | SERCOM_USART_CTRLA_TXPO(0x0);SERCOM5->USART.CTRLB.reg = SERCOM_USART_CTRLB_RXEN | SERCOM_USART_CTRLB_TXEN |SERCOM_USART_CTRLB_CHSIZE(0);SERCOM5->USART.BAUD.reg = (uint16_t)baudrate+1;SERCOM5->USART.CTRLA.reg |= SERCOM_USART_CTRLA_ENABLE;}Writing and main:Code:static void uart_putc(char c){while (!(SERCOM5->USART.INTFLAG.reg & SERCOM_USART_INTFLAG_DRE));SERCOM5->USART.DATA.reg = c;}static void uart_puts(char *s){while (*s)uart_putc(*s++);}int main(void){SystemInit();GPIO_Init();TMR_Init();uart_init2(115200);uart_puts("Hello, world!");while (1){}}The attachment show the output of the code that is used.The usart start whos the output from the start of the code and the rest are screenshots of the remaining output.The baudrate im trying to communicate on is 115200.

author: DavedenHaan
author_rank: Contributor
timestamp: November 17, 2020, 03:17:56 pm
content: It could have to do something with the timers and Clock that is connected I will add that as well.In case someone has a suggestionCode:#define TC3_PRESCALER4#define TC3_PER_10MS(80000/TC3_PRESCALER)-50#define GLOBAL_TMR_TO_100MS10#define GLOBAL_TMR_TO_1000MS100extern uint32_tGlobalTick;#define GLOBAL_TMR_SET(x)(x+GlobalTick)#define GLOBAL_TMR_IS_EXPIRED(x)(x <= GlobalTick)void TC3_Handler(void){TC3->COUNT16.INTFLAG.reg = TC_INTFLAG_OVF;GlobalTick++;}void TMR_Init(void){PM->APBCMASK.reg |= PM_APBCMASK_TC3;//Provide power to TC3GCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID(TC3_GCLK_ID) |GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN(0);//Provide Clock to TC3, from generator 0TC3->COUNT16.CTRLA.reg =TC_CTRLA_MODE_COUNT16 |// Configuring TC3 to 16-bit operationTC_CTRLA_WAVEGEN_MFRQ |// Match frequency wit CC0TC_CTRLA_PRESCALER_DIV4 |// Prescaler to 4TC_CTRLA_PRESCSYNC_RESYNC;// Reload or reset the counter on next generic clock. Reset the prescaler counterTC3->COUNT16.CC.reg = TC3_PER_10MS;// Set overflow valueTC3->COUNT16.COUNT.reg = 0;// Clear CounterTC3->COUNT16.INTFLAG.reg = TC_INTFLAG_OVF;// Clear interrupt flag of timer overflowTC3->COUNT16.INTENSET.reg = TC_INTENSET_OVF;// Enable interrupt on overflowNVIC_EnableIRQ(TC3_IRQn);// Enable Global Interrupt for the PeripheralTC3->COUNT16.CTRLA.reg |= TC_CTRLA_ENABLE;// Start Timer*/}

author: ataradov
author_rank: Super Contributor
timestamp: November 17, 2020, 05:17:41 pm
content: You are not showing any timings on your traces. Is your logic analyzer decoder actually configured for 115200? It does not look like it.

author: DavedenHaan
author_rank: Contributor
timestamp: November 17, 2020, 05:29:53 pm
content: Currently I have it set on 115200.I included all the settings that the UART let me do.The last screenshot shows the total time of the message.

author: ataradov
author_rank: Super Contributor
timestamp: November 17, 2020, 05:36:27 pm
content: Those timings are super hard to read. I'm not sure why logic analyzer authors keep making them this way.Do this. Send just one character - "U" and capture the result and a real close up of the whole transfer. Or better yet, attach the actual log instead of screen captures.Is your system clock actually 8 MHz?

author: DavedenHaan
author_rank: Contributor
timestamp: November 17, 2020, 05:41:14 pm
content: Included are the setting for the system clock.I will try your suggestion with the single character and the entire log from the analyzer.

author: DavedenHaan
author_rank: Contributor
timestamp: November 17, 2020, 05:47:32 pm
content: There are few options for exporting the analyzer output.The first attachment shows the available options, which one should I do?If this isn't what u meant I haven't used many logic analyzer like this so I'm still learning the possiblitiesThe other attachment is the output when sending just an 'U' the output is in HEX atm.

author: ataradov
author_rank: Super Contributor
timestamp: November 17, 2020, 05:49:38 pm
content: Quote from: DavedenHaan on November 17, 2020, 05:41:14 pmThis is not a setting, this is just a variable. Do you actually have the code that configures it to be 8 MHz?

author: ataradov
author_rank: Super Contributor
timestamp: November 17, 2020, 05:51:42 pm
content: Your baudrate is definitely not correct. You can see the character U (0x55) begin send, but the logic analyzer interprets each bit as a new byte.Don't do export, just do save. I nave PulseView, I can open those files in its native format. But in this case there is no need for a log, the situation is pretty clear.

author: DavedenHaan
author_rank: Contributor
timestamp: November 17, 2020, 05:55:46 pm
content: Nothing extra no, I thought this sets the system clock by including sytem_init() into the main.The only clock setting that are done are included in the first post for the timer and the GLCK that is done in the uart_init();timer:

author: ataradov
author_rank: Super Contributor
timestamp: November 17, 2020, 05:57:53 pm
content: It has nothing to do with the timer. There is no need to copy that code here.I have no idea what sytem_init() does. You seem to be just pulling random code from different places without looking at it. This is not a good idea.Just take my sys_init() from the same place you took the UART code.

author: DavedenHaan
author_rank: Contributor
timestamp: November 17, 2020, 06:07:38 pm
content: the system_init(); was created by Atmel itself when I started the project for the the SAMD21;It was included in the device startup.I have included the output of the pulseview.The sys_init(); for the 8MHz clock is included instead of the system_init();I had to include it as ZIP because it doesn't let me upload otherwise

author: ataradov
author_rank: Super Contributor
timestamp: November 17, 2020, 06:23:02 pm
content: This capture looks like it was done with a very low sampling rate on the analyzer or the frequency on the output jumped up a lot.What version of the sys_init() did you include? Can you share the entire project?

author: DavedenHaan
author_rank: Contributor
timestamp: November 17, 2020, 06:42:38 pm
content: I dont have a github set up will do that soon so its easier to read throughCode:HAL_GPIO_PIN(UART_TX,B,30)HAL_GPIO_PIN(UART_RX,B,31)static void uart_init2(uint32_t baud) // Uart init for SERCOM 5 pins{uint64_t br = (uint64_t)65536 * (8000000 - 16 * baud) / 8000000;HAL_GPIO_UART_TX_out();HAL_GPIO_UART_TX_pmuxen(PORT_PMUX_PMUXE_D_Val);HAL_GPIO_UART_RX_in();HAL_GPIO_UART_RX_pmuxen(PORT_PMUX_PMUXE_D_Val);PM->APBCMASK.reg |= PM_APBCMASK_SERCOM5;GCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID(SERCOM5_GCLK_ID_CORE) |GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN(0);SERCOM5->USART.CTRLA.reg =SERCOM_USART_CTRLA_DORD | SERCOM_USART_CTRLA_MODE_USART_INT_CLK |SERCOM_USART_CTRLA_RXPO(0x1) | SERCOM_USART_CTRLA_TXPO(0x0);SERCOM5->USART.CTRLB.reg = SERCOM_USART_CTRLB_RXEN | SERCOM_USART_CTRLB_TXEN |SERCOM_USART_CTRLB_CHSIZE(0/*8 bits*/);SERCOM5->USART.BAUD.reg = (uint16_t)br+1;SERCOM5->USART.CTRLA.reg |= SERCOM_USART_CTRLA_ENABLE;}static void sys_init(void){// Switch to 8MHz clock (disable prescaler)SYSCTRL->OSC8M.bit.PRESC = 0;}static void uart_putc(char c){while (!(SERCOM5->USART.INTFLAG.reg & SERCOM_USART_INTFLAG_DRE));SERCOM5->USART.DATA.reg = c;}static void uart_puts(char *s){while (*s)uart_putc(*s++);}MainCode:int main(void){sys_init();GPIO_Init();TMR_Init();uart_init2(115200);uart_puts("U");while (1){//uart_puts("hello world");}}these are the settings I'm using now

author: ataradov
author_rank: Super Contributor
timestamp: November 17, 2020, 06:44:07 pm
content: There is no need to copy the exact same code twice.What is in your sys_init()?

author: DavedenHaan
author_rank: Contributor
timestamp: November 17, 2020, 06:46:47 pm
content: Code:static void sys_init(void){// Switch to 8MHz clock (disable prescaler)SYSCTRL->OSC8M.bit.PRESC = 0;}

author: ataradov
author_rank: Super Contributor
timestamp: November 17, 2020, 06:52:34 pm
content: Ok, this is good.Now make sure that you set at least 12 MHz sampling frequency on the logic analyzer. And capture the "U" character again.

author: DavedenHaan
author_rank: Contributor
timestamp: November 17, 2020, 07:05:21 pm
content: I used 12MHz sampling and I indeed got a U out from the UART port:I also tried Hello, world after and got that + some extra.uart_puts("\r\nHello, world!\r\n"); is what used isntead of U.The first attachment shows the output on the logic analyzer. (50M samplings, 12MHz samping time)I also tried just uart_puts("Hello, world!");the output shows world but Hello does not get decoded: attachment 2 shows output.

author: ataradov
author_rank: Super Contributor
timestamp: November 17, 2020, 07:14:54 pm
content: Your signal looks fine. I think your logic analyzer fails to decode things. Just connect to the real UART receiver.

author: DavedenHaan
author_rank: Contributor
timestamp: November 17, 2020, 07:34:39 pm
content: Good to know thank you, once I have the LTM module connected to send data I will do that.Until then I'm using this to read data from SPI(can bus) and I2C (GPS).It is my first time setting up the UART this way so I'm curious to how I would use the uart_puts(); in other ways then just hello worldFor some outputs I want it to be able to print out a buffer that is filled.I could only think of a quick arduino example which would look like this: print(buf, HEX) to print the content of buf.Thankyou so much for the help again you are a lifesaver!

author: ataradov
author_rank: Super Contributor
timestamp: November 17, 2020, 07:44:16 pm
content: uart_puts() can print a buffer that is formatted.I have no idea what that arduino function is actually doing, but if it prints the buffer in hex, then it would look something like this (typed, not compiled, may have errors):Code:void print_buf(uint8_t *buf, int size){static char hex[] = "0123456789abcdef";for (int i = 0; i < size; i++){uart_putc(hex[(buf >> 4) & 0xf]);uart_putc(hex[buf & 0xf]);uart_putc(' ');}}