ArduinoCore-samd icon indicating copy to clipboard operation
ArduinoCore-samd copied to clipboard

Cannot set UART to 300 baud

Open keestux opened this issue 9 years ago • 4 comments

Hi,

Since the commit 20104a6c it is not possible to set the UART baudrate to 300 anymore. We're now using the fractional mode of the SERCOM and sercom->USART.BAUD.FRAC.BAUD can only hold 13 bits while at 300 baud you want to write 10000. It doesn't fit.

To be honest, I don't even know how accurate the 300 baud used to be before this change, but we only use it to emulate sending a break. And that is not possible anymore.

Should we perhaps switch to the non-fractional mode if we detect that there is an overflow of the 13 bits?

keestux avatar Jan 26 '17 21:01 keestux

Have the same issue. not working anymore... Need 300 Baud to init read smartmeter on IEC. Any news? Still open?

rogeralthaus avatar Dec 01 '22 17:12 rogeralthaus

I spent a couple of Hours on this... Arithmetic and Fractional mode end up in the same result: Overflow or inaccurate Baudrates on rates below 600. This is cause the Baudrate is an result of Clock/Divisor wich ends in a Baudrate 274 or 320, but no way for exact 300. The only way i found is to switch the Clocksource of SERCOM5 from 48MHz to 8MHz.

This worked for me on MKR1010

void SERCOM::initUART(SercomUartMode mode, SercomUartSampleRate sampleRate, uint32_t baudrate)
{
	initClockNVIC();

	// BEGIN: Workaround for
	// Cannot set UART to 300 baud #208 
	// https://github.com/arduino/ArduinoCore-samd/issues/208
	// 01.12.22 - Roger Althaus
	
	// Switch SERCOM timer on lower Baudrates from  GCLK0 48MHz to GCLK2 8MHz
	// to prevent Baud-Register overflows and troubles for Baudrates below 600.
	if (mode == UART_INT_CLOCK && sercom == SERCOM5 && baudrate < 600)
	{

		// Clockchange is based on following article
		// https://blog.thea.codes/understanding-the-sam-d21-clocks/

		baudrate = baudrate * 6;  // Clock is 6 Times slower, so we have to adjust Baudrate 

		/* Configure GCLK2's divider - in this case, no division - so just divide by one */
		GCLK->GENDIV.reg =
			GCLK_GENDIV_ID(2) |
			GCLK_GENDIV_DIV(1);

		/* Setup GCLK2 using the internal 8 MHz oscillator */
		GCLK->GENCTRL.reg =
			GCLK_GENCTRL_ID(2) |
			GCLK_GENCTRL_SRC_OSC8M |
			/* Improve the duty cycle. */
			GCLK_GENCTRL_IDC |
			GCLK_GENCTRL_GENEN;

		/* Wait for the write to complete */
		while (GCLK->STATUS.bit.SYNCBUSY) {};

		/* Connect GCLK2 to SERCOM5 */
		GCLK->CLKCTRL.reg =
			GCLK_CLKCTRL_CLKEN |
			GCLK_CLKCTRL_GEN_GCLK2 |
			GCLK_CLKCTRL_ID_SERCOM5_CORE;

		/* Wait for the write to complete. */
		while (GCLK->STATUS.bit.SYNCBUSY) {};

		PM->APBCMASK.reg |= PM_APBCMASK_SERCOM5;

		//At this point the peripheral is ready to use!You can software reset the peripheraland start configuring it as needed :
		//SERCOM0->SPI.CTRLA.bit.SWRST = 1;
		//while (SERCOM0->SPI.SYNCBUSY.bit.SWRST) {};
	}
	// END: Workaround

	resetUART();
	....

rogeralthaus avatar Dec 02 '22 08:12 rogeralthaus

It would be interesting to have this fixed as an official PR, since like the user above said, 300 baud is still used a lot in IEC smartmeters

nunomiguelferreira avatar Mar 19 '24 20:03 nunomiguelferreira