/** * \brief Configure 48MHz Clock for USB */ static void _ConfigureUsbClock(void) { /* Enable PLLB for USB */ PMC->CKGR_PLLBR = CKGR_PLLBR_DIVB(1) | CKGR_PLLBR_MULB(7) | CKGR_PLLBR_PLLBCOUNT_Msk; while((PMC->PMC_SR & PMC_SR_LOCKB) == 0); /* USB Clock uses PLLB */ PMC->PMC_USB = PMC_USB_USBDIV(1) /* /2 */ | PMC_USB_USBS; /* PLLB */ }
// Configure 48MHz Clock for USB void usb_configure_clock_48mhz(void) { // Use PLLB for USB #if (BOARD_MAINOSC == 16000000) PMC->CKGR_PLLBR = CKGR_PLLBR_DIVB(1) | CKGR_PLLBR_MULB(5) | CKGR_PLLBR_PLLBCOUNT_Msk; while((PMC->PMC_SR & PMC_SR_LOCKB) == 0); // divide by 2 use PLLB PMC->PMC_USB = PMC_USB_USBDIV(1) | PMC_USB_USBS; #elif (BOARD_MAINOSC == 12000000) PMC->CKGR_PLLBR = CKGR_PLLBR_DIVB(1) | CKGR_PLLBR_MULB(7) | CKGR_PLLBR_PLLBCOUNT_Msk; while((PMC->PMC_SR & PMC_SR_LOCKB) == 0); // divide by 2 use PLLB PMC->PMC_USB = PMC_USB_USBDIV(1) | PMC_USB_USBS; #endif }
static inline void sam_pmcsetup(void) { uint32_t regval; /* Enable main oscillator (if it has not already been selected) */ if ((getreg32(SAM_PMC_CKGR_MOR) & PMC_CKGR_MOR_MOSCSEL) == 0) { /* "When the MOSCXTEN bit and the MOSCXTCNT are written in CKGR_MOR to * enable the main oscillator, the MOSCXTS bit in the Power Management * Controller Status Register (PMC_SR) is cleared and the counter starts * counting down on the slow clock divided by 8 from the MOSCXTCNT * value. ... When the counter reaches 0, the MOSCXTS bit is set, * indicating that the main clock is valid." */ putreg32(BOARD_CKGR_MOR, SAM_PMC_CKGR_MOR); sam_pmcwait(PMC_INT_MOSCXTS); } /* "Switch to the main oscillator. The selection is made by writing the * MOSCSEL bit in the Main Oscillator Register (CKGR_MOR). The switch of * the Main Clock source is glitch free, so there is no need to run out * of SLCK, PLLACK or UPLLCK in order to change the selection. The MOSCSELS * bit of the power Management Controller Status Register (PMC_SR) allows * knowing when the switch sequence is done." * * MOSCSELS: Main Oscillator Selection Status * 0 = Selection is done * 1 = Selection is in progress */ putreg32((BOARD_CKGR_MOR | PMC_CKGR_MOR_MOSCSEL), SAM_PMC_CKGR_MOR); sam_pmcwait(PMC_INT_MOSCSELS); /* "Select the master clock. "The Master Clock selection is made by writing * the CSS field (Clock Source Selection) in PMC_MCKR (Master Clock Register). * The prescaler supports the division by a power of 2 of the selected clock * between 1 and 64, and the division by 3. The PRES field in PMC_MCKR programs * the prescaler. Each time PMC_MCKR is written to define a new Master Clock, * the MCKRDY bit is cleared in PMC_SR. It reads 0 until the Master Clock is * established. */ regval = getreg32(SAM_PMC_MCKR); regval &= ~PMC_MCKR_CSS_MASK; regval |= PMC_MCKR_CSS_MAIN; putreg32(regval, SAM_PMC_MCKR); sam_pmcwait(PMC_INT_MCKRDY); /* Setup PLLA and wait for LOCKA */ putreg32(BOARD_CKGR_PLLAR, SAM_PMC_CKGR_PLLAR); sam_pmcwait(PMC_INT_LOCKA); #ifdef CONFIG_SAMV7_USBDEVHS /* UTMI configuration: Enable port0, select 12/16 MHz MAINOSC crystal source */ #if BOARD_MAINOSC_FREQUENCY == 12000000 putreg32(UTMI_CKTRIM_FREQ_XTAL12, SAM_UTMI_CKTRIM); #elif BOARD_MAINOSC_FREQUENCY == 16000000 putreg32(UTMI_CKTRIM_FREQ_XTAL16, SAM_UTMI_CKTRIM); #else # error ERROR: Unrecognized MAINSOSC frequency #endif #ifdef CONFIG_SAMV7_USBDEVHS_LOWPOWER /* Enable UTMI Clocking. The USBHS can work in two modes: * * - Normal mode where High speed, Full speed and Low speed are available. * - Low-power mode where only Full speed and Low speed are available. * * Only the Low-power mode is mode is supported by the logic here. Normal * mode logic is handled in the function sam_usbclock(). */ /* UTMI Low-power mode, Full/Low Speed mode * * Enable the 48MHz FS Clock. */ putreg32(PMC_USBCLK, SAM_PMC_SCER); /* Select the UTMI PLL as the USB PLL clock input (480MHz) with divider * to get to 48MHz. UPLL output frequency is determined only by the * 12/16MHz crystal selection above. */ regval = PMC_USB_USBS_UPLL; if ((getreg32(SAM_PMC_MCKR) & PMC_MCKR_PLLADIV2) != 0) { /* Divider = 480 Mhz / 2 / 48 Mhz = 5 */ regval |= PMC_USB_USBDIV(4); } else { /* Divider = 480 Mhz / 1 / 48 Mhz = 10 */ regval |= PMC_USB_USBDIV(9); } putreg32(regval, SAM_PMC_USB); /* Enable the UTMI PLL with the maximum start-up time */ regval = PMC_CKGR_UCKR_UPLLEN | PMC_CKGR_UCKR_UPLLCOUNT_MAX; putreg32(regval, SAM_PMC_CKGR_UCKR); /* Wait for LOCKU */ sam_pmcwait(PMC_INT_LOCKU); #endif /* CONFIG_SAMV7_USBDEVHS_LOWPOWER */ #endif /* CONFIG_SAMV7_USBDEVHS */ /* Switch to the fast clock and wait for MCKRDY */ putreg32(BOARD_PMC_MCKR_FAST, SAM_PMC_MCKR); sam_pmcwait(PMC_INT_MCKRDY); putreg32(BOARD_PMC_MCKR, SAM_PMC_MCKR); sam_pmcwait(PMC_INT_MCKRDY); }
/** * \brief Switch UHP (USB) clock source selection to PLLB clock. * * \param ul_usbdiv Clock divisor. */ void pmc_switch_uhpck_to_pllbck(uint32_t ul_usbdiv) { PMC->PMC_USB = PMC_USB_USBDIV(ul_usbdiv) | PMC_USB_USBS; }
/** * \brief Switch UDP (USB) clock source selection to UPLL clock. * * \param ul_usbdiv Clock divisor. */ void pmc_switch_udpck_to_upllck(uint32_t ul_usbdiv) { PMC->PMC_USB = PMC_USB_USBS | PMC_USB_USBDIV(ul_usbdiv); }
// ペリフェラルの初期化 // RTX RTOSの開始前に呼ばれる extern "C" void init(void){ // WDTを無効にする WDT->WDT_MR = WDT_MR_WDIDLEHLT | WDT_MR_WDDBGHLT | (0xFFF << WDT_MR_WDD_Pos) | WDT_MR_WDDIS | (0xFFF << WDT_MR_WDV_Pos); // RSWDTは標準で無効になっている // BODリセットは標準で有効になっている // 1度、強制的にリセットする(OpenOCDによるデバッグのため) if (RESET_GPBR == 0){ RESET_GPBR = 1; RSTC->RSTC_CR = RSTC_CR_KEY_PASSWD | RSTC_CR_PERRST | RSTC_CR_PROCRST; }else{ RESET_GPBR = 0; } // FPUを有効にする SCB->CPACR = 0x00F00000; // キャッシュを有効にする(キャッシュはROMとFlash領域のみ有効) //CMCC->CMCC_CTRL = CMCC_CTRL_CEN; // フラッシュのウェイト数を設定 EFC->EEFC_FMR = EEFC_FMR_CLOE | EEFC_FMR_FWS(5); // 最大129MHz // システムクロックを設定 // SLCK=32kHz, MAINCK=12MHz, PLLACK=240MHz, USB_48M=48MHz, MCK=120MHz PMC->CKGR_MOR = CKGR_MOR_MOSCSEL | CKGR_MOR_KEY_PASSWD | CKGR_MOR_MOSCRCF_4_MHz | CKGR_MOR_MOSCRCEN | CKGR_MOR_MOSCXTBY; while(~PMC->PMC_SR & PMC_SR_MOSCSELS); PMC->CKGR_MOR = CKGR_MOR_MOSCSEL | CKGR_MOR_KEY_PASSWD | CKGR_MOR_MOSCXTBY; PMC->CKGR_PLLAR = CKGR_PLLAR_ONE | CKGR_PLLAR_MULA(20) | CKGR_PLLAR_PLLACOUNT(16) | CKGR_PLLAR_DIVA(1); while(~PMC->PMC_SR & PMC_SR_LOCKA); PMC->PMC_USB = PMC_USB_USBDIV(5 - 1); PMC->PMC_MCKR = PMC_MCKR_PRES_CLK_2 | PMC_MCKR_CSS_MAIN_CLK; while(~PMC->PMC_SR & PMC_SR_MCKRDY); PMC->PMC_MCKR = PMC_MCKR_PRES_CLK_2 | PMC_MCKR_CSS_PLLA_CLK; while(~PMC->PMC_SR & PMC_SR_MCKRDY); // クロック供給を有効にする // 31:AFEC1, 30:AFEC0, 23:TC2, 22:TC1, 21:TC0, 20:DMAC, 12:PIOD, 10:PIOB, 9:PIOA, 7:UART0 // 36:PWM, 35:UDP PMC->PMC_PCER0 = PMC_PCER0_PID31 | PMC_PCER0_PID30 | PMC_PCER0_PID23 | PMC_PCER0_PID22 | PMC_PCER0_PID21 | PMC_PCER0_PID20 | PMC_PCER0_PID12 | PMC_PCER0_PID10 | PMC_PCER0_PID9 | PMC_PCER0_PID7; PMC->PMC_PCER1 = PMC_PCER1_PID36 | PMC_PCER1_PID35; PMC->PMC_SCER = PMC_SCER_UDP; // NVICのベクターをRAMに移動 NVIC_Migration(); // I/Oピンの初期化 clDigitalIOInitializer IOInitializer; IOInitializer.Set(PIN_HOST_TX, DIR_IN, OUT_LOW, PINMODE_PU); IOInitializer.Set(PIN_HOST_RX, DIR_OUT, OUT_HIGH); IOInitializer.Set(PIN_CAM1_CLK, DIR_OUT, OUT_LOW); IOInitializer.Set(PIN_CAM2_CLK, DIR_OUT, OUT_LOW); IOInitializer.Set(PIN_CAM1_SI, DIR_OUT, OUT_LOW); IOInitializer.Set(PIN_CAM2_SI, DIR_OUT, OUT_LOW); IOInitializer.Set(PIN_CAM1_A0P, DIR_IN, OUT_LOW, PINMODE_PU); IOInitializer.Set(PIN_CAM2_A0P, DIR_IN, OUT_LOW, PINMODE_PU); IOInitializer.Set(PIN_USB_VBUS, DIR_IN, OUT_LOW); IOInitializer.Set(PIN_nSW1, DIR_IN, OUT_LOW, PINMODE_PU); IOInitializer.Set(PIN_LED1, DIR_OUT, OUT_LOW); IOInitializer.Set(PIN_LED_ENABLE, DIR_OUT, OUT_LOW); IOInitializer.Mux(PIN_HOST_TX, PINMUX_A, PIO_DISABLE); IOInitializer.Mux(PIN_HOST_RX, PINMUX_A, PIO_DISABLE); IOInitializer.Mux(PIN_CAM1_CLK, PINMUX_A, PIO_DISABLE); IOInitializer.Mux(PIN_CAM2_CLK, PINMUX_B, PIO_DISABLE); IOInitializer.Apply(); /* OSリソースの作成を伴わないデバイスインスタンスの初期化を行う */ }
static inline void sam_usbclockconfig(void) { #if defined(CONFIG_SAMA5_EHCI) || defined(CONFIG_SAMA5_OHCI) || \ defined(CONFIG_SAMA5_UDPHS) /* We can either get the clock from the UPLL or from PLLA. In this latter * case, however, the PLLACK frequency must be a multiple of 48MHz. */ #if defined(BOARD_USE_UPLL) uint32_t regval; /* The USB Host High Speed requires a 480 MHz clock (UPLLCK) for the * embedded High-speed transceivers. UPLLCK is the output of the 480 MHz * UTMI PLL (UPLL). The source clock of the UTMI PLL is the Main OSC output: * Either the 12MHz internal oscillator on a 12MHz crystal. The Main OSC * must be 12MHz because the UPLL has a built-in 40x multiplier. * * For High-speed operations, the user has to perform the following: * * 1) Enable UHP peripheral clock, bit (1 << AT91C_ID_UHPHS) in * PMC_PCER register. * 2) Write CKGR_PLLCOUNT field in PMC_UCKR register. * 3) Enable UPLL, bit AT91C_CKGR_UPLLEN in PMC_UCKR register. * 4) Wait until UTMI_PLL is locked. LOCKU bit in PMC_SR register * 5) Enable BIAS, bit AT91C_CKGR_BIASEN in PMC_UCKR register. * 6) Select UPLLCK as Input clock of OHCI part, USBS bit in PMC_USB * register. * 7) Program the OHCI clocks (UHP48M and UHP12M) with USBDIV field in * PMC_USB register. USBDIV must be 9 (division by 10) if UPLLCK is * selected. * 8) Enable OHCI clocks, UHP bit in PMC_SCER register. * * Steps 2 through 7 performed here. 1 and 8 are performed in the EHCI * driver is initialized. */ /* 2) Write CKGR_PLLCOUNT field in PMC_UCKR register. */ regval = PMC_CKGR_UCKR_UPLLCOUNT(BOARD_CKGR_UCKR_UPLLCOUNT); putreg32(regval, SAM_PMC_CKGR_UCKR); /* 3) Enable UPLL, bit AT91C_CKGR_UPLLEN in PMC_UCKR register. */ regval |= PMC_CKGR_UCKR_UPLLEN; putreg32(regval, SAM_PMC_CKGR_UCKR); /* 4) Wait until UTMI_PLL is locked. LOCKU bit in PMC_SR register */ sam_pmcwait(PMC_INT_LOCKU); /* 5) Enable BIAS, bit AT91C_CKGR_BIASEN in PMC_UCKR register. */ regval |= PMC_CKGR_UCKR_BIASCOUNT(BOARD_CKGR_UCKR_BIASCOUNT); putreg32(regval, SAM_PMC_CKGR_UCKR); regval |= PMC_CKGR_UCKR_BIASEN; putreg32(regval, SAM_PMC_CKGR_UCKR); /* 6) Select UPLLCK as Input clock of OHCI part, USBS bit in PMC_USB * register. */ regval = PMC_USB_USBS_UPLL; putreg32(regval, SAM_PMC_USB); /* 7) Program the OHCI clocks (UHP48M and UHP12M) with USBDIV field in * PMC_USB register. USBDIV must be 9 (division by 10) if UPLLCK is * selected. * * REVISIT: The divisor of 10 produces a rate that is too high with * SAMA5D3. A divisor of 5, however, seems to work just fine for the * SAMA5D3. The SAMA5D4, on the other hand, needs the divisor of 10. * No idea why? Let the board.h file decide which to use. */ regval |= PMC_USB_USBDIV(BOARD_UPLL_OHCI_DIV-1); putreg32(regval, SAM_PMC_USB); #else /* BOARD_USE_UPLL */ /* For OHCI Full-speed operations only, the user has to perform the * following: * * 1) Enable UHP peripheral clock, bit (1 << AT91C_ID_UHPHS) in PMC_PCER * register. * 2) Select PLLACK as Input clock of OHCI part, USBS bit in PMC_USB * register. * 3) Program the OHCI clocks (UHP48M and UHP12M) with USBDIV field in * PMC_USB register. USBDIV value is calculated regarding the PLLACK * value and USB Full-speed accuracy. * 4) Enable the OHCI clocks, UHP bit in PMC_SCER register. * * Steps 2 and 3 are done here. 1 and 2 are performed with the OHCI * driver is initialized. */ putreg32(BOARD_OHCI_INPUT | BOARD_OHCI_DIVIDER << PMC_USB_USBDIV_SHIFT, SAM_PMC_USB); #endif /* BOARD_USE_UPLL */ #endif /* CONFIG_SAMA5_EHCI ||CONFIG_SAMA5_OHCI) || CONFIG_SAMA5_UDPHS */ }