/* mbed Microcontroller Library * Copyright (c) 2006-2020 ARM Limited * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "pinmap.h" #include "clock_config.h" #include "fsl_clock.h" #include "fsl_xbara.h" #include "fsl_iomuxc.h" #include "fsl_gpio.h" #include "fsl_pit.h" #include "lpm.h" #include "usb_phy.h" #include "usb_device_config.h" #include "us_ticker_defines.h" #include "us_ticker_api.h" #define LPSPI_CLOCK_SOURCE_DIVIDER (7U) #define LPI2C_CLOCK_SOURCE_DIVIDER (5U) /* USB PHY condfiguration */ #define BOARD_USB_PHY_D_CAL (0x0CU) #define BOARD_USB_PHY_TXCAL45DP (0x06U) #define BOARD_USB_PHY_TXCAL45DM (0x06U) uint8_t mbed_otp_mac_address(char *mac); void mbed_default_mac_address(char *mac); /* MPU configuration. */ void BOARD_ConfigMPU(void) { /* Disable I cache and D cache */ if (SCB_CCR_IC_Msk == (SCB_CCR_IC_Msk & SCB->CCR)) { SCB_DisableICache(); } if (SCB_CCR_DC_Msk == (SCB_CCR_DC_Msk & SCB->CCR)) { SCB_DisableDCache(); } /* Disable MPU */ ARM_MPU_Disable(); /* MPU configure: * Use ARM_MPU_RASR(DisableExec, AccessPermission, TypeExtField, IsShareable, IsCacheable, IsBufferable, SubRegionDisable, Size) * API in mpu_armv7.h. * param DisableExec Instruction access (XN) disable bit,0=instruction fetches enabled, 1=instruction fetches disabled. * param AccessPermission Data access permissions, allows you to configure read/write access for User and Privileged mode. * Use MACROS defined in mpu_armv7.h: ARM_MPU_AP_NONE/ARM_MPU_AP_PRIV/ARM_MPU_AP_URO/ARM_MPU_AP_FULL/ARM_MPU_AP_PRO/ARM_MPU_AP_RO * Combine TypeExtField/IsShareable/IsCacheable/IsBufferable to configure MPU memory access attributes. * TypeExtField IsShareable IsCacheable IsBufferable Memory Attribtue Shareability Cache * 0 x 0 0 Strongly Ordered shareable * 0 x 0 1 Device shareable * 0 0 1 0 Normal not shareable Outer and inner write through no write allocate * 0 0 1 1 Normal not shareable Outer and inner write back no write allocate * 0 1 1 0 Normal shareable Outer and inner write through no write allocate * 0 1 1 1 Normal shareable Outer and inner write back no write allocate * 1 0 0 0 Normal not shareable outer and inner noncache * 1 1 0 0 Normal shareable outer and inner noncache * 1 0 1 1 Normal not shareable outer and inner write back write/read acllocate * 1 1 1 1 Normal shareable outer and inner write back write/read acllocate * 2 x 0 0 Device not shareable * Above are normal use settings, if your want to see more details or want to config different inner/outter cache policy. * please refer to Table 4-55 /4-56 in arm cortex-M7 generic user guide <dui0646b_cortex_m7_dgug.pdf> * param SubRegionDisable Sub-region disable field. 0=sub-region is enabled, 1=sub-region is disabled. * param Size Region size of the region to be configured. use ARM_MPU_REGION_SIZE_xxx MACRO in mpu_armv7.h. */ /* Region 0 setting: Memory with Device type, not shareable, non-cacheable. */ MPU->RBAR = ARM_MPU_RBAR(0, 0x80000000U); MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 2, 0, 0, 0, 0, ARM_MPU_REGION_SIZE_512MB); /* Region 1 setting: Memory with Device type, not shareable, non-cacheable. */ MPU->RBAR = ARM_MPU_RBAR(1, 0x60000000U); MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 2, 0, 0, 0, 0, ARM_MPU_REGION_SIZE_512MB); /* Region 2 setting */ #if defined(XIP_EXTERNAL_FLASH) && (XIP_EXTERNAL_FLASH == 1) /* Setting Memory with Normal type, not shareable, outer/inner write back. */ MPU->RBAR = ARM_MPU_RBAR(2, 0x60000000U); MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_RO, 0, 0, 1, 1, 0, ARM_MPU_REGION_SIZE_64MB); #endif /* Region 3 setting: Memory with Device type, not shareable, non-cacheable. */ MPU->RBAR = ARM_MPU_RBAR(3, 0x00000000U); MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 2, 0, 0, 0, 0, ARM_MPU_REGION_SIZE_1GB); /* Region 4 setting: Memory with Normal type, not shareable, outer/inner write back [ITCM] */ MPU->RBAR = ARM_MPU_RBAR(4, 0x00000000U); MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 0, 0, 1, 1, 0, ARM_MPU_REGION_SIZE_128KB); /* Region 5 setting: Memory with Normal type, not shareable, outer/inner write back [DTCM] */ MPU->RBAR = ARM_MPU_RBAR(5, 0x20000000U); MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 0, 0, 1, 1, 0, ARM_MPU_REGION_SIZE_256KB); #if MBED_TARGET_MIMXRT1050 /* Region 6 setting: Memory with Normal type, not shareable, outer/inner write back [OCRAM] */ MPU->RBAR = ARM_MPU_RBAR(6, 0x20200000U); MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 0, 0, 1, 1, 0, ARM_MPU_REGION_SIZE_128KB); #else // MIMXRT1060 /* Region 6 setting: Memory with Normal type, not shareable, outer/inner write back [OCRAM] */ MPU->RBAR = ARM_MPU_RBAR(6, 0x20280000U); MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 0, 0, 1, 1, 0, ARM_MPU_REGION_SIZE_128KB); /* Region 7 setting: Memory with Normal type, not shareable, outer/inner write back [OCRAM2] */ MPU->RBAR = ARM_MPU_RBAR(7, 0x20200000U); MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 0, 0, 1, 1, 0, ARM_MPU_REGION_SIZE_512KB); #endif /* The define sets the cacheable memory to shareable, * this suggestion is referred from chapter 2.2.1 Memory regions, * types and attributes in Cortex-M7 Devices, Generic User Guide */ #if defined(SDRAM_IS_SHAREABLE) /* Region 8 setting: Memory with Normal type, shareable, outer/inner write back, write/read allocate */ MPU->RBAR = ARM_MPU_RBAR(8, 0x80000000U); MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 1, 1, 1, 1, 0, ARM_MPU_REGION_SIZE_32MB); #else /* Region 8 setting: Memory with Normal type, not shareable, outer/inner write back, write/read allocate */ MPU->RBAR = ARM_MPU_RBAR(8, 0x80000000U); MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 1, 0, 1, 1, 0, ARM_MPU_REGION_SIZE_32MB); #endif /* Enable MPU */ ARM_MPU_Enable(MPU_CTRL_PRIVDEFENA_Msk); /* Enable I cache and D cache */ SCB_EnableDCache(); SCB_EnableICache(); } void BOARD_Init_PMIC_STBY_REQ(void) { CLOCK_EnableClock(kCLOCK_IomuxcSnvs); /* iomuxc_snvs clock (iomuxc_snvs_clk_enable): 0x03U */ /* GPIO configuration of PERI_PWREN on PMIC_STBY_REQ (pin L7) */ gpio_pin_config_t PERI_PWREN_config = { .direction = kGPIO_DigitalOutput, .outputLogic = 0U, .interruptMode = kGPIO_NoIntmode }; /* Initialize GPIO functionality on PMIC_STBY_REQ (pin L7) */ GPIO_PinInit(GPIO5, 2U, &PERI_PWREN_config); IOMUXC_SetPinMux( IOMUXC_SNVS_PMIC_STBY_REQ_GPIO5_IO02, /* PMIC_STBY_REQ is configured as GPIO5_IO02 */ 0U); /* Software Input On Field: Input Path is determined by functionality */ IOMUXC_SetPinConfig( IOMUXC_SNVS_PMIC_STBY_REQ_GPIO5_IO02, /* PMIC_STBY_REQ PAD functional properties : */ 0x10B0U); /* Slew Rate Field: Slow Slew Rate Drive Strength Field: R0/6 Speed Field: medium(100MHz) Open Drain Enable Field: Open Drain Disabled Pull / Keep Enable Field: Pull/Keeper Enabled Pull / Keep Select Field: Keeper Pull Up / Down Config. Field: 100K Ohm Pull Down Hyst. Enable Field: Hysteresis Disabled */ } // called before main void mbed_sdk_init() { BOARD_ConfigMPU(); #if MBED_CONF_TARGET_ENABLE_OVERDRIVE_MODE BOARD_ClockOverdrive(); #else BOARD_ClockFullSpeed(); #endif // Initialize us ticker before LPM, because LPM uses it for timing us_ticker_init(); #if TARGET_EVK /* Since SNVS_PMIC_STBY_REQ_GPIO5_IO02 will output a high-level signal under Stop Mode(Suspend Mode) and this pin is * connected to LCD power switch circuit. So it needs to be configured as a low-level output GPIO to reduce the * current. */ BOARD_Init_PMIC_STBY_REQ(); #endif LPM_Init(); } void spi_setup_clock() { // Not needed on MIMXRT105x } uint32_t spi_get_clock(void) { return BOARD_CLOCKFULLSPEED_LPSPI_CLK_ROOT; } uint32_t us_ticker_get_clock() { return BOARD_CLOCKFULLSPEED_PERCLK_CLK_ROOT; } uint32_t serial_get_clock(void) { return BOARD_CLOCKFULLSPEED_UART_CLK_ROOT; } void i2c_setup_clock() { // Not needed on MIMXRT105x } uint32_t i2c_get_clock() { return BOARD_CLOCKFULLSPEED_LPI2C_CLK_ROOT; } void pwm_setup(uint32_t instance) { /* Use default clock settings */ /* Set the PWM Fault inputs to a low value */ XBARA_Init(XBARA1); XBARA_SetSignalsConnection(XBARA1, kXBARA1_InputLogicHigh, kXBARA1_OutputFlexpwm1234Fault2); XBARA_SetSignalsConnection(XBARA1, kXBARA1_InputLogicHigh, kXBARA1_OutputFlexpwm1234Fault3); switch (instance) { case 1: XBARA_SetSignalsConnection(XBARA1, kXBARA1_InputLogicHigh, kXBARA1_OutputFlexpwm1Fault0); XBARA_SetSignalsConnection(XBARA1, kXBARA1_InputLogicHigh, kXBARA1_OutputFlexpwm1Fault1); break; case 2: XBARA_SetSignalsConnection(XBARA1, kXBARA1_InputLogicHigh, kXBARA1_OutputFlexpwm2Fault0); XBARA_SetSignalsConnection(XBARA1, kXBARA1_InputLogicHigh, kXBARA1_OutputFlexpwm2Fault1); break; case 3: XBARA_SetSignalsConnection(XBARA1, kXBARA1_InputLogicHigh, kXBARA1_OutputFlexpwm3Fault0); XBARA_SetSignalsConnection(XBARA1, kXBARA1_InputLogicHigh, kXBARA1_OutputFlexpwm3Fault1); break; case 4: XBARA_SetSignalsConnection(XBARA1, kXBARA1_InputLogicHigh, kXBARA1_OutputFlexpwm4Fault0); XBARA_SetSignalsConnection(XBARA1, kXBARA1_InputLogicHigh, kXBARA1_OutputFlexpwm4Fault1); break; default: break; } } uint32_t pwm_get_clock() { return CLOCK_GetFreq(kCLOCK_IpgClk); } // Change the NMI pin to an input. This allows NMI pin to // be used as a low power mode wakeup. The application will // need to change the pin back to NMI_b or wakeup only occurs once! void NMI_Handler(void) { pin_function(WAKEUP, 7); pin_mode(WAKEUP, PullDefault); } void mbed_mac_address(char *mac) { if (mbed_otp_mac_address(mac)) { return; } else { mbed_default_mac_address(mac); } return; } uint8_t mbed_otp_mac_address(char *mac) { #if TARGET_MIMXRT1050_EVK /* Check if a valid MAC address is programmed to the fuse bank */ if ((OCOTP->MAC0 != 0) && (OCOTP->MAC1 != 0) && (OCOTP->GP3 != 0)) { uint16_t MAC[3]; // 3 16 bits words for the MAC // Read the MAC address from the OCOTP MAC registers MAC[0] = (uint16_t)OCOTP->MAC0; // most significant half-word MAC[1] = (uint16_t)OCOTP->MAC1; MAC[2] = (uint16_t)OCOTP->GP3; // least significant half word // The network stack expects an array of 6 bytes // so we copy, and shift and copy from the half-word array to the byte array mac[0] = MAC[0] >> 8; mac[1] = MAC[0]; mac[2] = MAC[1] >> 8; mac[3] = MAC[1]; mac[4] = MAC[2] >> 8; mac[5] = MAC[2]; return 1; } #endif #if TARGET_TEENSY_4X if(OCOTP->MAC0 != 0 || OCOTP->MAC1 != 0) { mac[0] = OCOTP->MAC1 >> 8; mac[1] = OCOTP->MAC1 >> 0; mac[2] = OCOTP->MAC0 >> 24; mac[3] = OCOTP->MAC0 >> 16; mac[4] = OCOTP->MAC0 >> 8; mac[5] = OCOTP->MAC0 >> 0; return 1; } #endif return 0; } void mbed_default_mac_address(char *mac) { mac[0] = 0x00; mac[1] = 0x02; mac[2] = 0xF7; mac[3] = 0xF0; mac[4] = 0x00; mac[5] = 0x00; return; } void USB_DeviceClockInit(void) { usb_phy_config_struct_t phyConfig = { BOARD_USB_PHY_D_CAL, BOARD_USB_PHY_TXCAL45DP, BOARD_USB_PHY_TXCAL45DM, }; CLOCK_EnableUsbhs0PhyPllClock(kCLOCK_Usbphy480M, 480000000U); CLOCK_EnableUsbhs0Clock(kCLOCK_Usb480M, 480000000U); USB_EhciPhyInit(CONTROLLER_ID, BOARD_XTAL0_CLK_HZ, &phyConfig); } uint32_t USB_DeviceGetIrqNumber(void) { uint8_t irqNumber; uint8_t usbDeviceEhciIrq[] = USBHS_IRQS; irqNumber = usbDeviceEhciIrq[CONTROLLER_ID - kUSB_ControllerEhci0]; return irqNumber; } #if MBED_CONF_TARGET_ENABLE_OVERDRIVE_MODE #define LPM_POWER_MODE LPM_PowerModeOverRun #else #define LPM_POWER_MODE LPM_PowerModeFullRun #endif void vPortPRE_SLEEP_PROCESSING(clock_mode_t powermode) { LPM_EnableWakeupSource(GPT2_IRQn); LPM_EnterLowPowerIdle(LPM_POWER_MODE); // Disable us ticker during deep sleep. // Note: Must do this last because SDK_DelayAtLeastUs() uses the us ticker PIT_StopTimer(PIT, kPIT_Chnl_0); PIT_StopTimer(PIT, kPIT_Chnl_2); } void vPortPOST_SLEEP_PROCESSING(clock_mode_t powermode) { // reenable us ticker // Note: Must do this first because SDK_DelayAtLeastUs() uses the us ticker PIT_StartTimer(PIT, kPIT_Chnl_0); PIT_StartTimer(PIT, kPIT_Chnl_2); LPM_ExitLowPowerIdle(LPM_POWER_MODE); LPM_DisableWakeupSource(GPT2_IRQn); } // Override of MIMXRT SDK delay function. // The default delay function used the full CPU clock frequency, so it produced massive overshoots // (delaying 30x longer than intended) when the MCU is exiting sleep (and core clock is reduced to 24MHz). // This delay function uses the us ticker which always ticks at the same speed even when the CPU clock is reduced. void SDK_DelayAtLeastUs(uint32_t delay_us) { uint32_t initialTickerValue = us_ticker_read(); uint32_t targetTickerValue = delay_us + initialTickerValue; // Wait for rollover if needed if(targetTickerValue < initialTickerValue) { while(us_ticker_read() > initialTickerValue) {} } // Wait until target time while(us_ticker_read() < targetTickerValue) {} }