summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHa Thach <[email protected]>2021-03-23 20:39:20 +0700
committerGitHub <[email protected]>2021-03-23 20:39:20 +0700
commit59d0d255d8895b3fa1194db570b0f14348baa6b8 (patch)
treed7d66aae5bad4ea822b712519c089927a3cdf279
parent60f3ea5e810daab8249f5dad01e96367915d719e (diff)
parent8e6f298aa163fe92547e4b8a207c71e7edf2ab26 (diff)
Merge pull request #717 from jgressmann/feat/same54xplainedpro-free-pll1
SAM E54 XPlained Pro: free PLL1 for application
-rw-r--r--hw/bsp/same54xplainedpro/board.mk6
-rw-r--r--hw/bsp/same54xplainedpro/same54xplainedpro.c71
2 files changed, 54 insertions, 23 deletions
diff --git a/hw/bsp/same54xplainedpro/board.mk b/hw/bsp/same54xplainedpro/board.mk
index 7325a5ffb..16ac786d5 100644
--- a/hw/bsp/same54xplainedpro/board.mk
+++ b/hw/bsp/same54xplainedpro/board.mk
@@ -1,6 +1,6 @@
DEPS_SUBMODULES += hw/mcu/microchip
-CONF_CPU_FREQUENCY ?= 120000000
+CONF_CPU_FREQUENCY ?= 48000000
CFLAGS += \
-mthumb \
@@ -12,9 +12,9 @@ CFLAGS += \
-nostdlib -nostartfiles \
-D__SAME54P20A__ \
-DCONF_CPU_FREQUENCY=$(CONF_CPU_FREQUENCY) \
- -DCFG_TUSB_MCU=OPT_MCU_SAME5X
+ -DCFG_TUSB_MCU=OPT_MCU_SAME5X \
+ -DBOARD_NAME="\"Microchip SAM E54 Xplained Pro\""
-# -DSVC_Handler=SVCall_Handler
# All source paths should be relative to the top level.
LD_FILE = hw/bsp/$(BOARD)/same54p20a_flash.ld
diff --git a/hw/bsp/same54xplainedpro/same54xplainedpro.c b/hw/bsp/same54xplainedpro/same54xplainedpro.c
index a1d920757..4c38fc6eb 100644
--- a/hw/bsp/same54xplainedpro/same54xplainedpro.c
+++ b/hw/bsp/same54xplainedpro/same54xplainedpro.c
@@ -58,9 +58,20 @@ void USB_3_Handler(void)
#define LED_PIN PIN_PC18
#define BUTTON_PIN PIN_PB31
#define BOARD_SERCOM SERCOM2
-#define BOARD_NAME "Microchip SAM E54 Xplained Pro"
-static inline void init_clock(void)
+/** Initializes the clocks from the external 12 MHz crystal
+ *
+ * The goal of this setup is to preserve the second PLL
+ * for the application code while still having a reasonable
+ * 48 MHz clock for USB / UART.
+ *
+ * GCLK0: CONF_CPU_FREQUENCY (default 120 MHz) from PLL0
+ * GCLK1: unused
+ * GCLK2: 12 MHz from XOSC1
+ * DFLL48M: closed loop from GLCK2
+ * GCLK3: 48 MHz
+ */
+static inline void init_clock_xtal(void)
{
/* configure for a 12MHz crystal connected to XIN1/XOUT1 */
OSCCTRL->XOSCCTRL[1].reg =
@@ -72,16 +83,11 @@ static inline void init_clock(void)
OSCCTRL_XOSCCTRL_ENABLE;
while(0 == OSCCTRL->STATUS.bit.XOSCRDY1);
- OSCCTRL->Dpll[0].DPLLCTRLB.reg = OSCCTRL_DPLLCTRLB_DIV(5) | OSCCTRL_DPLLCTRLB_REFCLK_XOSC1; /* 12MHz / 12 = 1Mhz, input = XOSC1 */
- OSCCTRL->Dpll[0].DPLLRATIO.reg = OSCCTRL_DPLLRATIO_LDRFRAC(0x0) | OSCCTRL_DPLLRATIO_LDR((CONF_CPU_FREQUENCY / 1000000)-1); /* multiply to get CONF_CPU_FREQUENCY (default = 120MHz) */
+ OSCCTRL->Dpll[0].DPLLCTRLB.reg = OSCCTRL_DPLLCTRLB_DIV(2) | OSCCTRL_DPLLCTRLB_REFCLK_XOSC1; /* 12MHz / 6 = 2Mhz, input = XOSC1 */
+ OSCCTRL->Dpll[0].DPLLRATIO.reg = OSCCTRL_DPLLRATIO_LDRFRAC(0x0) | OSCCTRL_DPLLRATIO_LDR((CONF_CPU_FREQUENCY / 1000000 / 2) - 1); /* multiply to get CONF_CPU_FREQUENCY (default = 120MHz) */
OSCCTRL->Dpll[0].DPLLCTRLA.reg = OSCCTRL_DPLLCTRLA_RUNSTDBY | OSCCTRL_DPLLCTRLA_ENABLE;
while(0 == OSCCTRL->Dpll[0].DPLLSTATUS.bit.CLKRDY); /* wait for the PLL0 to be ready */
- OSCCTRL->Dpll[1].DPLLCTRLB.reg = OSCCTRL_DPLLCTRLB_DIV(5) | OSCCTRL_DPLLCTRLB_REFCLK_XOSC1; /* 12MHz / 12 = 1Mhz, input = XOSC1 */
- OSCCTRL->Dpll[1].DPLLRATIO.reg = OSCCTRL_DPLLRATIO_LDRFRAC(0x0) | OSCCTRL_DPLLRATIO_LDR(47); /* multiply by 48 -> 48 MHz */
- OSCCTRL->Dpll[1].DPLLCTRLA.reg = OSCCTRL_DPLLCTRLA_RUNSTDBY | OSCCTRL_DPLLCTRLA_ENABLE;
- while(0 == OSCCTRL->Dpll[1].DPLLSTATUS.bit.CLKRDY); /* wait for the PLL1 to be ready */
-
/* configure clock-generator 0 to use DPLL0 as source -> GCLK0 is used for the core */
GCLK->GENCTRL[0].reg =
GCLK_GENCTRL_DIV(0) |
@@ -91,23 +97,47 @@ static inline void init_clock(void)
GCLK_GENCTRL_IDC;
while(1 == GCLK->SYNCBUSY.bit.GENCTRL0); /* wait for the synchronization between clock domains to be complete */
- /* configure clock-generator 1 to use DPLL1 as source -> for use with some peripheral */
- GCLK->GENCTRL[1].reg =
+ // configure GCLK2 for 12MHz from XOSC1
+ GCLK->GENCTRL[2].reg =
+ GCLK_GENCTRL_DIV(0) |
+ GCLK_GENCTRL_RUNSTDBY |
+ GCLK_GENCTRL_GENEN |
+ GCLK_GENCTRL_SRC_XOSC1 |
+ GCLK_GENCTRL_IDC;
+ while(1 == GCLK->SYNCBUSY.bit.GENCTRL2); /* wait for the synchronization between clock domains to be complete */
+
+ /* setup DFLL48M to use GLCK2 */
+ GCLK->PCHCTRL[OSCCTRL_GCLK_ID_DFLL48].reg = GCLK_PCHCTRL_GEN_GCLK2 | GCLK_PCHCTRL_CHEN;
+
+ OSCCTRL->DFLLCTRLA.reg = 0;
+ while(1 == OSCCTRL->DFLLSYNC.bit.ENABLE);
+
+ OSCCTRL->DFLLCTRLB.reg = OSCCTRL_DFLLCTRLB_MODE | OSCCTRL_DFLLCTRLB_WAITLOCK;
+ OSCCTRL->DFLLMUL.bit.MUL = 4; // 4 * 12MHz -> 48MHz
+
+ OSCCTRL->DFLLCTRLA.reg =
+ OSCCTRL_DFLLCTRLA_ENABLE |
+ OSCCTRL_DFLLCTRLA_RUNSTDBY;
+ while(1 == OSCCTRL->DFLLSYNC.bit.ENABLE);
+
+ // setup 48 MHz GCLK3 from DFLL48M
+ GCLK->GENCTRL[3].reg =
GCLK_GENCTRL_DIV(0) |
GCLK_GENCTRL_RUNSTDBY |
GCLK_GENCTRL_GENEN |
- GCLK_GENCTRL_SRC_DPLL1 |
- GCLK_GENCTRL_IDC ;
- while(1 == GCLK->SYNCBUSY.bit.GENCTRL1); /* wait for the synchronization between clock domains to be complete */
+ GCLK_GENCTRL_SRC_DFLL |
+ GCLK_GENCTRL_IDC;
+ while(1 == GCLK->SYNCBUSY.bit.GENCTRL3);
}
+/* Initialize SERCOM2 for 115200 bps 8N1 using a 48 MHz clock */
static inline void uart_init(void)
{
gpio_set_pin_function(PIN_PB24, PINMUX_PB24D_SERCOM2_PAD1);
gpio_set_pin_function(PIN_PB25, PINMUX_PB25D_SERCOM2_PAD0);
MCLK->APBBMASK.bit.SERCOM2_ = 1;
- GCLK->PCHCTRL[SERCOM2_GCLK_ID_CORE].reg = GCLK_PCHCTRL_GEN_GCLK1 | GCLK_PCHCTRL_CHEN; /* setup SERCOM to use GLCK1 -> 48MHz */
+ GCLK->PCHCTRL[SERCOM2_GCLK_ID_CORE].reg = GCLK_PCHCTRL_GEN_GCLK0 | GCLK_PCHCTRL_CHEN;
BOARD_SERCOM->USART.CTRLA.bit.SWRST = 1; /* reset and disable SERCOM -> enable configuration */
while (BOARD_SERCOM->USART.SYNCBUSY.bit.SWRST);
@@ -127,7 +157,7 @@ static inline void uart_init(void)
// BOARD_SERCOM->USART.BAUD.reg = SERCOM_USART_BAUD_FRAC_FP(0) | SERCOM_USART_BAUD_FRAC_BAUD(26); /* 48000000/(16*115200) = 26.041666667 */
BOARD_SERCOM->USART.BAUD.reg = SERCOM_USART_BAUD_BAUD(63019); /* 65536*(1−16*115200/48000000) */
- BOARD_SERCOM->SPI.CTRLA.bit.ENABLE = 1; /* activate SERCOM */
+ BOARD_SERCOM->USART.CTRLA.bit.ENABLE = 1; /* activate SERCOM */
while (BOARD_SERCOM->USART.SYNCBUSY.bit.ENABLE); /* wait for SERCOM to be ready */
}
@@ -135,7 +165,7 @@ static inline void uart_send_buffer(uint8_t const *text, size_t len)
{
for (size_t i = 0; i < len; ++i) {
BOARD_SERCOM->USART.DATA.reg = text[i];
- while((BOARD_SERCOM->USART.INTFLAG.reg & SERCOM_SPI_INTFLAG_TXC) == 0);
+ while((BOARD_SERCOM->USART.INTFLAG.reg & SERCOM_USART_INTFLAG_TXC) == 0);
}
}
@@ -143,14 +173,15 @@ static inline void uart_send_str(const char* text)
{
while (*text) {
BOARD_SERCOM->USART.DATA.reg = *text++;
- while((BOARD_SERCOM->USART.INTFLAG.reg & SERCOM_SPI_INTFLAG_TXC) == 0);
+ while((BOARD_SERCOM->USART.INTFLAG.reg & SERCOM_USART_INTFLAG_TXC) == 0);
}
}
void board_init(void)
{
- init_clock();
+ // Uncomment this line and change the GCLK for UART/USB to run off the XTAL.
+ // init_clock_xtal();
SystemCoreClock = CONF_CPU_FREQUENCY;
@@ -201,7 +232,7 @@ void board_init(void)
* The USB module requires a GCLK_USB of 48 MHz ~ 0.25% clock
* for low speed and full speed operation.
*/
- hri_gclk_write_PCHCTRL_reg(GCLK, USB_GCLK_ID, GCLK_PCHCTRL_GEN_GCLK1_Val | GCLK_PCHCTRL_CHEN);
+ hri_gclk_write_PCHCTRL_reg(GCLK, USB_GCLK_ID, GCLK_PCHCTRL_GEN_GCLK0_Val | GCLK_PCHCTRL_CHEN);
hri_mclk_set_AHBMASK_USB_bit(MCLK);
hri_mclk_set_APBBMASK_USB_bit(MCLK);