Change Arduino Zero clock speed or UART clock speed for 1 Mbaud serial output

I need to send serial output at exactly 1 Mbaud, and it is not working correctly with the Zero running at 48 Mhz. I ran into a similar issue with the Due, but I was able to find some code that allowed me to reset the clock rate from 88 to 80 Mhz so it could generate the correct serial buad rate. (Here is a link to the post I found related to this: [Solved] Arduino Due UART with 500kbps - Arduino Due - Arduino Forum) I have been looking for something similar to this for the Zero, but have not been able to find anything. I also started looking through the data sheet and code, but so far I have not had much luck understanding how to change this. Does anyone know how to change the system clock speed on the Zero, or of some way to get the serial port to use a clock that can generate a 1 Mbaud signal?

It looks like I jumped the gun blaming the clock speed. It turned out it was a different issue with my sketch. When I dug into it more I found that the Zero does not have that same clock speed issue as the Due, and that it can generate 1 Mbaud signals just fine. It would still be nice to know how to adjust the clock speed though if anyone knows that?

I think you want page 113 of the data sheet.
http://www.atmel.com/Images/Atmel-42181-SAM-D21_Datasheet.pdf

I'm struggling with understanding the right way to access/use these registers using C in the Arduino IDE (if this is even possible). If you could share some code here I would be very grateful.

The Serial1 port uses SERCOM0 and it seems that there are two ways to calculate the value to put into the BAUD register (page 434 of the datasheet):

  1. Arithmetic mode: BAUD = 65536 * (1 - S * 1M / 48M)

  2. Fractional mode: BAUD = 48M / (S * 1M) - FP/8

where:

  • FP is a 3-bit value (0...7)
  • S is the number of samples per bit, it can be 16, 8 or 3.

To achieve a perfect division I can see:

  1. set S=3 and we get BAUD=61440 with a perfect division

  2. a possible solution is FP=0, S=16 that gives BAUD=3

To implement 1) you can do:

SERCOM0->USART.CTRLA.bit.SAMPR = 0x4; // 0x4 -> 3x over-sampling using arithmetic baud rate generation.
SERCOM0->USART.BAUD.reg = 61440;

to implement 2):

SERCOM0->USART.CTRLA.bit.SAMPR = 0x1; // 0x1 -> 16x over-sampling using fractional baud rate generation.
SERCOM0->USART.BAUD.reg = 3; // this implies also FP=0 because FP is BAUD[15..13]

Disclaimer: totally untested, take it as a quick and dirty try.