/***************************************************************************//** * @file * @brief System Peripheral API ******************************************************************************* * # License * Copyright 2018 Silicon Laboratories Inc. www.silabs.com ******************************************************************************* * * SPDX-License-Identifier: Zlib * * The licensor of this software is Silicon Laboratories Inc. * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. * ******************************************************************************/ #include "em_system.h" #include "sl_assert.h" #include #if defined(SYSCFG_PRESENT) #include "em_syscfg.h" #endif /***************************************************************************//** * @addtogroup system * @{ ******************************************************************************/ /******************************************************************************* ********************************* DEFINES ********************************* ******************************************************************************/ /** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */ /* Bit mask used to extract the part number value without the new naming * bitfield. */ #define SYSCFG_CHIPREV_PARTNUMBER1 0xFE0 #define SYSCFG_CHIPREV_PARTNUMBER0 0xF /* Bit mask to convert NON-SECURE to SECURE */ #define CONVERT_NS_TO_S (~(1 << 28U)) /** @endcond */ /******************************************************************************* ************************** GLOBAL FUNCTIONS ******************************* ******************************************************************************/ /***************************************************************************//** * @brief * Get a chip major/minor revision. * * @param[out] rev * A location to place the chip revision information. ******************************************************************************/ void SYSTEM_ChipRevisionGet(SYSTEM_ChipRevision_TypeDef *rev) { #if defined(_SYSCFG_CHIPREV_FAMILY_MASK) || defined(_SYSCFG_CHIPREV_PARTNUMBER_MASK) /* On series-2 (and higher) the revision info is in the SYSCFG->CHIPREV register. */ uint32_t chiprev = SYSCFG_readChipRev(); #if defined(_SYSCFG_CHIPREV_PARTNUMBER_MASK) rev->partNumber = ((chiprev & SYSCFG_CHIPREV_PARTNUMBER1) >> 5) | (chiprev & SYSCFG_CHIPREV_PARTNUMBER0); #else rev->family = (chiprev & _SYSCFG_CHIPREV_FAMILY_MASK) >> _SYSCFG_CHIPREV_FAMILY_SHIFT; #endif rev->major = (chiprev & _SYSCFG_CHIPREV_MAJOR_MASK) >> _SYSCFG_CHIPREV_MAJOR_SHIFT; rev->minor = (chiprev & _SYSCFG_CHIPREV_MINOR_MASK) >> _SYSCFG_CHIPREV_MINOR_SHIFT; #else uint8_t tmp; EFM_ASSERT(rev); /* CHIP FAMILY bit [5:2] */ tmp = (uint8_t)(((ROMTABLE->PID1 & _ROMTABLE_PID1_FAMILYMSB_MASK) >> _ROMTABLE_PID1_FAMILYMSB_SHIFT) << 2); /* CHIP FAMILY bit [1:0] */ tmp |= (uint8_t)((ROMTABLE->PID0 & _ROMTABLE_PID0_FAMILYLSB_MASK) >> _ROMTABLE_PID0_FAMILYLSB_SHIFT); rev->family = tmp; /* CHIP MAJOR bit [3:0] */ rev->major = (uint8_t)((ROMTABLE->PID0 & _ROMTABLE_PID0_REVMAJOR_MASK) >> _ROMTABLE_PID0_REVMAJOR_SHIFT); /* CHIP MINOR bit [7:4] */ tmp = (uint8_t)(((ROMTABLE->PID2 & _ROMTABLE_PID2_REVMINORMSB_MASK) >> _ROMTABLE_PID2_REVMINORMSB_SHIFT) << 4); /* CHIP MINOR bit [3:0] */ tmp |= (uint8_t)((ROMTABLE->PID3 & _ROMTABLE_PID3_REVMINORLSB_MASK) >> _ROMTABLE_PID3_REVMINORLSB_SHIFT); rev->minor = tmp; #endif } /***************************************************************************//** * @brief * Get a factory calibration value for a given peripheral register. * * @param[in] regAddress * The peripheral calibration register address to get a calibration value for. If * the calibration value is found, this register is updated with the * calibration value. * * @return * True if a calibration value exists, false otherwise. ******************************************************************************/ bool SYSTEM_GetCalibrationValue(volatile uint32_t *regAddress) { SYSTEM_CalAddrVal_TypeDef * p, * end; uint32_t s_regAddress = (uint32_t)regAddress; s_regAddress = s_regAddress & CONVERT_NS_TO_S; #if defined(MSC_FLASH_CHIPCONFIG_MEM_BASE) p = (SYSTEM_CalAddrVal_TypeDef *)MSC_FLASH_CHIPCONFIG_MEM_BASE; end = (SYSTEM_CalAddrVal_TypeDef *)MSC_FLASH_CHIPCONFIG_MEM_END; #else p = (SYSTEM_CalAddrVal_TypeDef *)(DEVINFO_BASE & 0xFFFFF000U); end = (SYSTEM_CalAddrVal_TypeDef *)DEVINFO_BASE; #endif for (; p < end; p++) { if (p->address == 0) { /* p->address == 0 marks the end of the table */ return false; } if (p->address == s_regAddress) { *regAddress = p->calValue; return true; } } /* Nothing found for regAddress. */ return false; } /***************************************************************************//** * @brief * Get family security capability. * * @note * This function retrieves the family security capability based on the * device number. The device number is one letter and 3 digits: * DEVICENUMBER = (alpha-'A')*1000 + numeric. i.e. 0d = "A000"; 1123d = "B123". * The security capabilities are represented by ::SYSTEM_SecurityCapability_TypeDef. * * @return * Security capability of MCU. ******************************************************************************/ SYSTEM_SecurityCapability_TypeDef SYSTEM_GetSecurityCapability(void) { SYSTEM_SecurityCapability_TypeDef sc; #if (_SILICON_LABS_32B_SERIES == 0) sc = securityCapabilityNA; #elif (_SILICON_LABS_32B_SERIES == 1) sc = securityCapabilityBasic; #else sc = securityCapabilityUnknown; #endif #if (_SILICON_LABS_32B_SERIES == 2) uint16_t mcuFeatureSetMajor; uint16_t deviceNumber; deviceNumber = SYSTEM_GetPartNumber(); mcuFeatureSetMajor = 'A' + (deviceNumber / 1000); #if defined(_SILICON_LABS_32B_SERIES_2_CONFIG_2) // override feature set since BRD4182A Rev A00 -> rev B02 are marked "A" mcuFeatureSetMajor = 'C'; #endif switch (mcuFeatureSetMajor) { case 'A': sc = securityCapabilitySE; break; case 'B': sc = securityCapabilityVault; break; case 'C': sc = securityCapabilityRoT; break; default: sc = securityCapabilityUnknown; break; } #endif return sc; } /***************************************************************************//** * @brief * Get the unique number for this device. * * @return * Unique number for this device. ******************************************************************************/ uint64_t SYSTEM_GetUnique(void) { #if defined (_DEVINFO_EUI64H_MASK) uint32_t tmp = DEVINFO->EUI64L; return (uint64_t)((uint64_t)DEVINFO->EUI64H << 32) | tmp; #elif defined(_DEVINFO_UNIQUEH_MASK) uint32_t tmp = DEVINFO->UNIQUEL; return (uint64_t)((uint64_t)DEVINFO->UNIQUEH << 32) | tmp; #else #error (em_system.c): Location of device unique number is not defined. #endif } /***************************************************************************//** * @brief * Get the production revision for this part. * * @return * Production revision for this part. ******************************************************************************/ uint8_t SYSTEM_GetProdRev(void) { #if defined (_DEVINFO_PART_PROD_REV_MASK) return (uint8_t)((DEVINFO->PART & _DEVINFO_PART_PROD_REV_MASK) >> _DEVINFO_PART_PROD_REV_SHIFT); #elif defined (_DEVINFO_INFO_PRODREV_MASK) return (uint8_t)((DEVINFO->INFO & _DEVINFO_INFO_PRODREV_MASK) >> _DEVINFO_INFO_PRODREV_SHIFT); #else #error (em_system.c): Location of production revision is not defined. #endif } /***************************************************************************//** * @brief * Get the SRAM Base Address. * * @note * This function is used to retrieve the base address of the SRAM. * * @return * Base address SRAM (32-bit unsigned integer). ******************************************************************************/ uint32_t SYSTEM_GetSRAMBaseAddress(void) { return (uint32_t)SRAM_BASE; } /***************************************************************************//** * @brief * Get the SRAM size (in KB). * * @note * This function retrieves SRAM size by reading the chip device * info structure. If your binary is made for one specific device only, * use SRAM_SIZE instead. * * @return * Size of internal SRAM (in KB). ******************************************************************************/ uint16_t SYSTEM_GetSRAMSize(void) { uint16_t sizekb; #if defined(_EFM32_GECKO_FAMILY) /* Early Gecko devices had a bug where SRAM and Flash size were swapped. */ if (SYSTEM_GetProdRev() < 5) { sizekb = (DEVINFO->MSIZE & _DEVINFO_MSIZE_FLASH_MASK) >> _DEVINFO_MSIZE_FLASH_SHIFT; } #endif sizekb = (uint16_t)((DEVINFO->MSIZE & _DEVINFO_MSIZE_SRAM_MASK) >> _DEVINFO_MSIZE_SRAM_SHIFT); #if defined(_SILICON_LABS_GECKO_INTERNAL_SDID_80) && defined(_EFR_DEVICE) /* Do not include EFR32xG1 RAMH. */ sizekb--; #endif return sizekb; } /***************************************************************************//** * @brief * Get the flash size (in KB). * * @note * This function retrieves flash size by reading the chip device * info structure. If your binary is made for one specific device only, * use FLASH_SIZE instead. * * @return * Size of internal flash (in KB). ******************************************************************************/ uint16_t SYSTEM_GetFlashSize(void) { #if defined(_EFM32_GECKO_FAMILY) /* Early Gecko devices had a bug where SRAM and Flash size were swapped. */ if (SYSTEM_GetProdRev() < 5) { return (DEVINFO->MSIZE & _DEVINFO_MSIZE_SRAM_MASK) >> _DEVINFO_MSIZE_SRAM_SHIFT; } #endif return (uint16_t)((DEVINFO->MSIZE & _DEVINFO_MSIZE_FLASH_MASK) >> _DEVINFO_MSIZE_FLASH_SHIFT); } /***************************************************************************//** * @brief * Get the flash page size in bytes. * * @note * This function retrieves flash page size by reading the chip device * info structure. If your binary is made for one specific device only, * use FLASH_PAGE_SIZE instead. * * @return * Page size of internal flash in bytes. ******************************************************************************/ uint32_t SYSTEM_GetFlashPageSize(void) { uint32_t tmp; #if defined(_SILICON_LABS_32B_SERIES_0) #if defined(_EFM32_GIANT_FAMILY) if (SYSTEM_GetProdRev() < 18) { /* Early Giant/Leopard devices did not have MEMINFO in DEVINFO. */ return FLASH_PAGE_SIZE; } #elif defined(_EFM32_ZERO_FAMILY) if (SYSTEM_GetProdRev() < 24) { /* Early Zero devices have an incorrect DEVINFO flash page size */ return FLASH_PAGE_SIZE; } #endif #endif #if defined(_DEVINFO_MEMINFO_FLASHPAGESIZE_MASK) tmp = (DEVINFO->MEMINFO & _DEVINFO_MEMINFO_FLASHPAGESIZE_MASK) >> _DEVINFO_MEMINFO_FLASHPAGESIZE_SHIFT; #elif defined(_DEVINFO_MEMINFO_FLASH_PAGE_SIZE_MASK) tmp = (DEVINFO->MEMINFO & _DEVINFO_MEMINFO_FLASH_PAGE_SIZE_MASK) >> _DEVINFO_MEMINFO_FLASH_PAGE_SIZE_SHIFT; #else #error (em_system.c): Location of flash page size is not defined. #endif return 1UL << ((tmp + 10UL) & 0x1FUL); } /***************************************************************************//** * @brief * Get the MCU part number. * * @return * The part number of MCU. ******************************************************************************/ uint16_t SYSTEM_GetPartNumber(void) { #if defined(_DEVINFO_PART_DEVICENUM_MASK) return (uint16_t)((DEVINFO->PART & _DEVINFO_PART_DEVICENUM_MASK) >> _DEVINFO_PART_DEVICENUM_SHIFT); #elif defined(_DEVINFO_PART_DEVICE_NUMBER_MASK) return (uint16_t)((DEVINFO->PART & _DEVINFO_PART_DEVICE_NUMBER_MASK) >> _DEVINFO_PART_DEVICE_NUMBER_SHIFT); #else #error (em_system.c): Location of device part number is not defined. #endif } /***************************************************************************//** * @brief * Get the calibration temperature (in degrees Celsius). * * @return * Calibration temperature in Celsius. ******************************************************************************/ uint8_t SYSTEM_GetCalibrationTemperature(void) { #if defined(_DEVINFO_CAL_TEMP_MASK) return (uint8_t)((DEVINFO->CAL & _DEVINFO_CAL_TEMP_MASK) >> _DEVINFO_CAL_TEMP_SHIFT); #elif defined(_DEVINFO_CALTEMP_TEMP_MASK) return (uint8_t)((DEVINFO->CALTEMP & _DEVINFO_CALTEMP_TEMP_MASK) >> _DEVINFO_CALTEMP_TEMP_SHIFT); #else #error (em_system.c): Location of calibration temperature is not defined. #endif } /***************************************************************************//** * @brief * Get the MCU family identifier. * * @note * This function retrieves family ID by reading the chip's device info * structure in flash memory. Users can retrieve family ID directly * by reading DEVINFO->PART item and decode with mask and shift * \#defines defined in \_devinfo.h (refer to code * below for details). * * @return * Family identifier of MCU. ******************************************************************************/ SYSTEM_PartFamily_TypeDef SYSTEM_GetFamily(void) { #if defined(_DEVINFO_PART_FAMILY_MASK) return (SYSTEM_PartFamily_TypeDef) ((uint32_t)((DEVINFO->PART & (_DEVINFO_PART_FAMILY_MASK | _DEVINFO_PART_FAMILYNUM_MASK)))); #elif defined(_DEVINFO_PART_DEVICE_FAMILY_MASK) return (SYSTEM_PartFamily_TypeDef) ((uint32_t)((DEVINFO->PART & _DEVINFO_PART_DEVICE_FAMILY_MASK) >> _DEVINFO_PART_DEVICE_FAMILY_SHIFT)); #else #error (em_system.h): Location of device family name is not defined. #endif } /** @} (end addtogroup system) */