Initial commit of firmware

This commit is contained in:
2025-04-12 13:30:57 +01:00
commit 264a3462e0
374 changed files with 332649 additions and 0 deletions

View File

@@ -0,0 +1,99 @@
/***************************************************************************//**
* @file
* @brief API "assert" implementation.
*******************************************************************************
* # License
* <b>Copyright 2021 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* 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.
*
******************************************************************************/
#ifndef SL_ASSERT_H
#define SL_ASSERT_H
#ifdef __cplusplus
extern "C" {
#endif
#if defined(DOXY_DOC_ONLY)
/** Included for documentation purposes only. This define is not present by default.
* DEBUG_EFM should be defined from the compiler to enable the default internal
* assert handler. */
#define DEBUG_EFM
#endif
#if defined(DEBUG_EFM) || defined(DEBUG_EFM_USER)
/***************************************************************************//**
* @addtogroup assert ASSERT - Assert
* @brief Assert/error checking module
* @details
* By default, library assert usage is not included to reduce
* footprint and processing overhead. Further, assert usage is decoupled
* from ISO C assert handling (NDEBUG usage) to allow using ISO C
* assert without including assert statements.
*
* Below are available defines for controlling assert inclusion. The defines
* are typically for a project to be used by the preprocessor.
*
* @li If DEBUG_EFM is defined, the internal library assert handling will
* be used. This is implemented as a simple while(true) loop. DEBUG_EFM is not
* defined by default.
*
* @li If DEBUG_EFM_USER is defined, the user must provide custom
* implementation of the assertEFM() function.
*
* @li If both DEBUG_EFM and DEBUG_EFM_USER are undefined, all EFM_ASSERT()
* statements are not operational.
*
* @note
* The internal assert is documented because DEBUG_EFM is defined in
* the doxygen configuration.
* @{
******************************************************************************/
/* Due to footprint considerations, we only pass file name and line number, */
/* not the assert expression (nor function name (C99)) */
/***************************************************************************//**
* @brief
* Assert function for EFM.
* @param[in] file - path and file name of the assert.
*
* @param[in] line - line number, in the file.
******************************************************************************/
void assertEFM(const char *file, int line);
/** Default assertion is not operational */
#define EFM_ASSERT(expr) ((expr) ? ((void)0) : assertEFM(__FILE__, __LINE__))
#else
/** Default assertion is not operational */
#define EFM_ASSERT(expr) ((void)(expr))
#endif /* defined(DEBUG_EFM) || defined(DEBUG_EFM_USER) */
/** @} (end addtogroup assert) */
#ifdef __cplusplus
}
#endif
#endif /* SL_ASSERT_H */

View File

@@ -0,0 +1,80 @@
/*******************************************************************************
* @file
* @brief Implementation of atomic operations.
*******************************************************************************
* # License
* <b>Copyright 2019 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* 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.
*
******************************************************************************/
#ifndef SL_ATOMIC_H
#define SL_ATOMIC_H
/*******************************************************************************
* @addtogroup atomic Atomic Operations
* @brief Atomic operations provide RAM store and read functionalities.
* @n @section atomic_usage Atomic Operations Usage
* @{
******************************************************************************/
/***************************************************************************//**
* @brief Perform an atomic load. Use when a variable must be read from
* RAM.
*
* @param dest Variable where to copy the loaded value.
*
* @param source Variable from where to load the value.
*
* @note Does only support native types <= 32 bits.
*
* @note Load operation on 32 bit value is atomic on ARM architecture.
*
* @note Only the load operation from 'source' is guaranteed to be
* performed atomically. If writing to 'dest' implies a store,
* the load and store operations are not guaranteed to be
* performed atomically.
******************************************************************************/
#define sl_atomic_load(dest, source) ((dest) = (source))
/*******************************************************************************
* @brief Perform an atomic store. Use when a value must be stored in
* RAM.
*
* @param dest Variable where to store the value.
*
* @param source Variable that contains the value to store in 'dest'.
*
* @note Does only support native types <= 32 bits.
*
* @note Store operation on 32 bit value is atomic on ARM architecture.
*
* @note Only the store operation to 'dest' is guaranteed to be
* performed atomically. If reading from 'source' implies a load,
* the store and load operations are not guaranteed to be
* performed atomically.
******************************************************************************/
#define sl_atomic_store(dest, source) ((dest) = (source))
/** @} (end addtogroup atomic) */
#endif /* SL_ATOMIC_H */

View File

@@ -0,0 +1,189 @@
/***************************************************************************//**
* @file
* @brief Implementation of bit operations.
*******************************************************************************
* # License
* <b>Copyright 2019 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* 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.
*
******************************************************************************/
#ifndef SL_BIT_H
#define SL_BIT_H
/***************************************************************************//**
* @addtogroup bit Bit Manipulation
* @brief Bitwise operations
* @{
******************************************************************************/
/****************************************************************************************************//**
* SL_DEF_BIT()
*
* @brief Create bit mask with single, specified bit set.
*
* @param bit Bit number of bit to set.
*
* @return Bit mask with single, specified bit set.
*
* @note (1) 'bit' SHOULD be a non-negative integer.
*
* @note (2) 'bit' values that overflow the target CPU &/or compiler environment (e.g. negative
* or greater-than-CPU-data-size values) MAY generate compiler warnings &/or errors.
*******************************************************************************************************/
#define SL_DEF_BIT(bit) (1u << (bit))
/****************************************************************************************************//**
* SL_SET_BIT()
*
* @brief Set specified bit(s) in a value.
*
* @param val Value to modify by setting specified bit(s).
*
* @param mask Mask of bits to set.
*
* @return Modified value with specified bit(s) set.
*
* @note 'val' & 'mask' SHOULD be unsigned integers.
*******************************************************************************************************/
#define SL_SET_BIT(val, mask) ((val) = ((val) | (mask)))
/****************************************************************************************************//**
* SL_CLEAR_BIT()
*
* @brief Clear specified bit(s) in a value.
*
* @param val Value to modify by clearing specified bit(s).
*
* @param mask Mask of bits to clear.
*
* @return Modified value with specified bit(s) clear.
*
* @note 'val' & 'mask' SHOULD be unsigned integers.
*
* @note 'mask' SHOULD be cast with the same data type than 'val'.
*******************************************************************************************************/
#define SL_CLEAR_BIT(val, mask) ((val) = ((val) & (~(mask))))
/****************************************************************************************************//**
* SL_IS_BIT_SET()
*
* @brief Determine whether the specified bit(s) in a value are set.
*
* @param val Value to check for specified bit(s) set.
*
* @param mask Mask of bits to check if set.
*
* @return true, if ALL specified bit(s) are set in value.
*
* false, if ALL specified bit(s) are NOT set in value.
*
* @note 'val' & 'mask' SHOULD be unsigned integers.
*
* @note NULL 'mask' allowed; returns 'false' since NO mask bits specified.
*******************************************************************************************************/
#define SL_IS_BIT_SET(val, mask) (((((val) & (mask)) == (mask)) && ((mask) != 0u)) ? (true) : (false))
/****************************************************************************************************//**
* SL_IS_BIT_CLEAR()
*
* @brief Determine whether the specified bit(s) in a value are clear.
*
* @param val Value to check for specified bit(s) clear.
*
* @param mask Mask of bits to check if clear.
*
* @return true, if ALL specified bit(s) are clear in value.
*
* false, if ALL specified bit(s) are NOT clear in value.
*
* @note val' & 'mask' SHOULD be unsigned integers.
*
* @note NULL 'mask' allowed; returns 'false' since NO mask bits specified.
*******************************************************************************************************/
#define SL_IS_BIT_CLEAR(val, mask) (((((val) & (mask)) == 0u) && ((mask) != 0u)) ? (true) : (false))
/****************************************************************************************************//**
* SL_IS_ANY_BIT_SET()
*
* @brief Determine whether any specified bit(s) in a value are set.
*
* @param val Value to check for specified bit(s) set.
*
* @param mask Mask of bits to check if set (see Note #2).
*
* @return true, if ANY specified bit(s) are set in value.
*
* false, if ALL specified bit(s) are NOT set in value.
*
* @note 'val' & 'mask' SHOULD be unsigned integers.
*
* @note NULL 'mask' allowed; returns 'false' since NO mask bits specified.
*******************************************************************************************************/
#define SL_IS_ANY_BIT_SET(val, mask) ((((val) & (mask)) == 0u) ? (false) : (true))
/****************************************************************************************************//**
* SL_IS_ANY_BIT_CLEAR()
*
* @brief Determine whether any specified bit(s) in a value are clear.
*
* @param val Value to check for specified bit(s) clear.
*
* @param mask Mask of bits to check if clear (see Note #2).
*
* @return true, if ANY specified bit(s) are clear in value.
*
* false, if ALL specified bit(s) are NOT clear in value.
*
* @note 'val' & 'mask' SHOULD be unsigned integers.
*
* @note NULL 'mask' allowed; returns 'false' since NO mask bits specified.
*******************************************************************************************************/
#define SL_IS_ANY_BIT_CLEAR(val, mask) ((((val) & (mask)) == (mask)) ? (false) : (true))
/****************************************************************************************************//**
* SL_MATH_IS_PWR2()
*
* @brief Determine if a value is a power of 2.
*
* @param val Value.
*
* @return true, 'val' is a power of 2.
* false, 'val' is not a power of 2.
*******************************************************************************************************/
#define SL_MATH_IS_PWR2(val) ((((val) != 0u) && (((val) & ((val) - 1u)) == 0u)) ? true : false)
/*******************************************************************************
****************************** DEFINES ************************************
******************************************************************************/
/** @} (end addtogroup bit) */
#endif /* SL_BIT_H */

View File

@@ -0,0 +1,200 @@
/***************************************************************************//**
* @file sl_cmsis_os2_common.h
* @brief OS-agnostic header to provide CMSIS OS-Specific APIs like typedefs.
* @version x.y.z
*******************************************************************************
* # License
* <b>Copyright 2020 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* 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.
*
******************************************************************************/
#ifndef SL_CMSIS_OS2_COMMON_H
#define SL_CMSIS_OS2_COMMON_H
#include <stdint.h>
#include "cmsis_os2.h"
#include "sl_status.h"
#if defined(SL_COMPONENT_CATALOG_PRESENT)
#include "sl_component_catalog.h"
#endif
// Validate the chosen RTOS
#if !defined(SL_CATALOG_FREERTOS_KERNEL_PRESENT) && !defined(SL_CATALOG_MICRIUMOS_KERNEL_PRESENT)
#error "The extended CMSIS RTOS2 API currently only supports FreeRTOS or MicriumOS"
#endif
#if defined(SL_CATALOG_FREERTOS_KERNEL_PRESENT)
#include "FreeRTOS.h"
#elif defined(SL_CATALOG_MICRIUMOS_KERNEL_PRESENT)
#include "os.h"
#endif
#if defined(SL_CATALOG_FREERTOS_KERNEL_PRESENT)
#define osEventFlagsCbSize sizeof(StaticEventGroup_t)
#define osThreadCbSize sizeof(StaticTask_t)
#define osTimerCbSize sizeof(StaticTimer_t)
#define osMutexCbSize sizeof(StaticSemaphore_t)
#define osSemaphoreCbSize sizeof(StaticSemaphore_t)
#define osMessageQueueCbSize sizeof(StaticQueue_t)
#define osAlignment (portBYTE_ALIGNMENT)
typedef StaticEventGroup_t osEventFlags_t;
typedef StaticTask_t osThread_t;
typedef StaticTimer_t osTimer_t;
typedef StaticSemaphore_t osMutex_t;
typedef StaticSemaphore_t osSemaphore_t;
typedef StaticQueue_t osMessageQueue_t;
#elif defined(SL_CATALOG_MICRIUMOS_KERNEL_PRESENT)
typedef struct {
OS_TCB tcb; // This must be the first element, used by OSTCBCurPtr
#if (OS_CFG_FLAG_EN == DEF_ENABLED)
OS_FLAG_GRP flag_grp;
#endif
#if (OS_CFG_MUTEX_EN == DEF_ENABLED)
OS_MUTEX join_mutex;
#endif
uint8_t obj_dyn_alloc;
uint8_t stack_dyn_alloc;
uint32_t attr_bits;
} osThread_t;
#if (CMSIS_RTOS2_TIMER_TASK_EN == DEF_ENABLED)
typedef struct {
sl_sleeptimer_timer_handle_t handle;
osTimerFunc_t callback;
void *callback_data;
osTimerType_t type;
const char *name;
uint8_t dyn_alloc;
} osTimer_t;
#endif
#if (OS_CFG_FLAG_EN == DEF_ENABLED)
typedef struct {
OS_FLAG_GRP flag_grp;
uint8_t dyn_alloc;
uint32_t flags;
} osEventFlags_t;
#endif
#if (OS_CFG_MUTEX_EN == DEF_ENABLED)
typedef struct {
OS_MUTEX mutex;
uint8_t dyn_alloc;
uint8_t recursive;
} osMutex_t;
#endif
#if (OS_CFG_SEM_EN == DEF_ENABLED)
typedef struct {
OS_SEM sem;
uint8_t dyn_alloc;
uint32_t max_ctr;
} osSemaphore_t;
#endif
#if (OS_CFG_SEM_EN == DEF_ENABLED)
typedef struct {
OS_SEM sem_put;
OS_SEM sem_get;
uint8_t *buf;
uint8_t obj_dyn_alloc;
uint8_t buf_dyn_alloc;
uint32_t msg_count;
uint32_t msg_size;
uint32_t msg_queued;
uint32_t msg_head;
uint32_t msg_tail;
} osMessageQueue_t;
#endif
#if (OS_CFG_SEM_EN == DEF_ENABLED)
typedef struct {
OS_SEM sem;
uint8_t *buf;
uint8_t obj_dyn_alloc;
uint8_t buf_dyn_alloc;
uint32_t block_count;
uint32_t block_size;
uint32_t free_count;
uint32_t free_head;
} osMemoryPool_t;
#endif
#if (OS_CFG_FLAG_EN == DEF_ENABLED)
#define osEventFlagsCbSize sizeof(osEventFlags_t)
#endif
#define osThreadCbSize sizeof(osThread_t)
#if (OS_CFG_TMR_EN == DEF_ENABLED)
#define osTimerCbSize sizeof(osTimer_t)
#endif
#if (OS_CFG_MUTEX_EN == DEF_ENABLED)
#define osMutexCbSize sizeof(osMutex_t)
#endif
#if (OS_CFG_SEM_EN == DEF_ENABLED)
#define osSemaphoreCbSize sizeof(osSemaphore_t)
#endif
#if (OS_CFG_SEM_EN == DEF_ENABLED)
#define osMessageQueueCbSize sizeof(osMessageQueue_t)
#endif
#if (OS_CFG_SEM_EN == DEF_ENABLED)
#define osMemoryPoolCbSize sizeof(osMemoryPool_t)
#endif
#define osAlignment sizeof(CPU_ALIGN)
#endif // SL_CATALOG_MICRIUMOS_KERNEL_PRESENT
// -----------------------------------------------------------------------------
// Functions
#ifdef __cplusplus
extern "C" {
#endif
/********************************************************************************************************
* sl_cmsis_os_convert_status()
*
* @brief Convert OsStatus from CMSIS-RTOS2 to sl_status type.
*
* @param os_status The OS status code returned by CMSIS-RTOS2 API.
*
* @return Status code converted to sl_status.
*******************************************************************************************************/
sl_status_t sl_cmsis_os_convert_status(osStatus_t os_status);
#ifdef __cplusplus
}
#endif
#endif // SL_CMSIS_OS2_COMMON_H

View File

@@ -0,0 +1,75 @@
/***************************************************************************//**
* @file
* @brief Code Classification API
*******************************************************************************
* # License
* <b>Copyright 2023 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* 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.
*
******************************************************************************/
#ifndef _SL_CODE_CLASSIFICATION_H_
#define _SL_CODE_CLASSIFICATION_H_
#include "sli_code_classification.h"
// NOTE: This API is for use by applications only.
/**************************************************************************//**
* @addtogroup code_placement
* @brief Code Classification API
* @{
*****************************************************************************/
/******************************************************************************/
/* Macro API */
/******************************************************************************/
#if defined(__GNUC__) && !defined(__llvm__)
// With GCC, __attribute__ can be used to specify the input section of
// functions.
/// Prepend a function definition with this macro to place it in RAM.
#define SL_CODE_RAM \
__attribute__((section("text_application_ram")))
#elif defined(__ICCARM__)
// With IAR, _Pragma can be used to specify the input section of
// functions.
/// Prepend a function definition with this macro to place it in RAM.
#define SL_CODE_RAM \
_Pragma("location =\"text_application_ram\"")
#elif defined(__llvm__)
#define SL_CODE_RAM
#else
#error "(sl_code_classification.h): Code classification does not support \
the chosen compiler."
#endif // __GNUC__
/** @} (end addtogroup code_placement) */
#endif // _SL_CODE_CLASSIFICATION_H_

View File

@@ -0,0 +1,420 @@
/***************************************************************************//**
* @file
* @brief General purpose utilities.
*******************************************************************************
* # License
* <b>Copyright 2021 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* 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.
*
******************************************************************************/
#ifndef SL_COMMON_H
#define SL_COMMON_H
#include <stdint.h>
#include <stdbool.h>
#include "sl_assert.h"
#ifdef __cplusplus
extern "C" {
#endif
#if !defined(__STATIC_INLINE)
#if !defined(__unix__) && defined(__arm__)
/* Compiler agnostic definitions */
#include "cmsis_compiler.h"
#elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
#define __STATIC_INLINE static inline
#else
#warning Please provide a macro for your compiler and architecture
#define __STATIC_INLINE static
#endif
#endif
/***************************************************************************//**
* @addtogroup common COMMON - Common Utilities
* @brief General purpose utilities and cross-compiler support
* @details
* This SDK supports the following compilers/IDEs:
* @li Simplicity Studio
* @li IAR Embedded Workbench
* @li Keil uVision IDE
* @li Plain armgcc
*
* Certain compiler features such as alignment is implemented differently in the tools.
* Therefore, macros such as @ref SL_ALIGN are provided to enable compiler independent
* code.
*
* @note RAM code macros are implemented in [RAMFUNC](/gecko-platform/<docspace-docleaf-version>/emlib-efm32g/).
* Cross-compiler RAM code support needs extended documentation and it is therefore
* implemented as a separate module.
*
* @{
******************************************************************************/
/** @brief Macros to concatenate. */
#define _CONCAT_2(first, second) first ## second
#define SL_CONCAT_PASTER_2(first, second) _CONCAT_2(first, second) ///< sl concat paster 2.
#define _CONCAT_3(first, second, third) first ## second ## third
#define SL_CONCAT_PASTER_3(first, second, third) _CONCAT_3(first, second, third) ///< sl concat paster 3.
#define _CONCAT_4(first, second, third, fourth) first ## second ## third ## fourth
#define SL_CONCAT_PASTER_4(first, second, third, fourth) _CONCAT_4(first, second, third, fourth) ///< sl concat paster 4.
/** @brief Round n up to closest interval of i. */
#define SL_CEILING(n, i) ((((n) + (i) - 1U) / (i)) * (i))
/** @brief Round n down to closest interval of i. */
#define SL_FLOOR(n, i) ((n / i) * i)
/** @brief Stringify X */
#define STRINGIZE(X) #X
#if !defined(__GNUC__)
/* Not GCC compilers */
/** @brief Macros for giving the compiler hints about the likelihood of a branch. */
#define SL_BRANCH_LIKELY(x) (x)
#define SL_BRANCH_UNLIKELY(x) (x)
/** @brief Macro for getting minimum value. */
#define SL_MIN(a, b) ((a) < (b) ? (a) : (b))
/** @brief Macro for getting maximum value. */
#define SL_MAX(a, b) ((a) > (b) ? (a) : (b))
/** @brief Macros for handling packed structures. */
#define SL_PACK_START(X) _Pragma(STRINGIZE(pack(X)))
#define SL_PACK_END() _Pragma("pack()")
#define SL_ATTRIBUTE_PACKED
#if defined(__CC_ARM)
/** @brief MDK-ARM compiler: Macros for handling aligned structures. */
#define SL_ALIGN(X) __align(X)
/** MDK-ARM compiler: Macro for handling weak symbols. */
#define SL_WEAK __attribute__ ((weak))
/** MDK-ARM compiler: Macro for handling non-returning functions. */
#define SL_NORETURN __attribute__ ((noreturn))
/** MDK-ARM compiler: Macro for handling section placement */
#define SL_ATTRIBUTE_SECTION(X) __attribute__ ((section(X)))
#endif
#if defined(__ICCARM__)
#if (__VER__ >= 8000000)
/** @brief Obsoleted macro from version 8.00 and on . */
#define _STD_BEGIN
/** @brief Obsoleted macro from version 8.00 and on . */
#define _STD_END
#endif
/** @brief IAR Embedded Workbench: Macros for handling aligned structures. */
#define SL_ALIGN(X) _Pragma(STRINGIZE(data_alignment = X))
/** @brief IAR Embedded Workbench: Macros for handling weak symbols. */
#define SL_WEAK __weak
/** @brief IAR Embedded Workbench: Macro for handling non-returning functions. */
#define SL_NORETURN __noreturn
/* *INDENT-OFF* */
/** IAR Embedded Workbench: Macro for handling section placement */
#define SL_ATTRIBUTE_SECTION(X) @ X
#endif
/* *INDENT-ON* */
#define SL_ATTRIBUTE_ALIGN(X)
/** @brief Macro for notifying the compiler of an intended
* switch case fallthrough. */
#define SL_FALLTHROUGH
/** @brief A macro for notifying the compiler to ignore type limit check. */
#define SL_IGNORE_TYPE_LIMIT_BEGIN
#define SL_IGNORE_TYPE_LIMIT_END
#else // !defined(__GNUC__)
/* GCC compilers */
/** @brief Macros for giving the compiler hints about the likelihood of a branch. */
#define SL_BRANCH_LIKELY(x) __builtin_expect(!!(x), 1)
#define SL_BRANCH_UNLIKELY(x) __builtin_expect(!!(x), 0)
/** @brief A macro for getting the minimum value. No side-effects, a and b are evaluated one time only. */
#define SL_MIN(a, b) __extension__({ __typeof__(a)_a = (a); __typeof__(b)_b = (b); _a < _b ? _a : _b; })
/** @brief A macro for getting the maximum value. No side-effects, a and b are evaluated one time only. */
#define SL_MAX(a, b) __extension__({ __typeof__(a)_a = (a); __typeof__(b)_b = (b); _a > _b ? _a : _b; })
/** @brief A GCC style macro for handling packed structures. */
#define SL_ATTRIBUTE_PACKED __attribute__ ((packed))
/** @brief A macro for handling packed structures.
* @n Use this macro before the structure definition.
* @n X denotes the maximum alignment of structure members. X is not supported with
* GCC. GCC always uses 1 byte maximum alignment.
*/
#define SL_PACK_START(x)
/** @brief A macro for handling packed structures.
* @n Use this macro after the structure definition.
* @n With GCC, add SL_ATTRIBUTE_PACKED after the closing curly braces of the structure
* definition.
*/
#define SL_PACK_END()
/** @brief GCC style macro for aligning a variable. */
#define SL_ATTRIBUTE_ALIGN(X) __attribute__ ((aligned(X)))
/** @brief A macro for aligning a variable.
* @n Use this macro before the variable definition.
* @n X denotes the storage alignment value in bytes.
* @n To be GCC-compatible, use SL_ATTRIBUTE_ALIGN(X) before the semicolon on normal
* variables. Use SL_ATTRIBUTE_ALIGN(X) before the opening curly brace on structure variables.
*/
#define SL_ALIGN(X)
/** @brief A macro for defining a weak symbol. */
#define SL_WEAK __attribute__ ((weak))
/** @brief A macro for handling non-returning functions. */
#define SL_NORETURN __attribute__ ((noreturn))
/** A macro for placing a variable in a section.
* @n Use this macro after the variable definition, before the equal sign or a semicolon.
* @n X denotes the section to place the variable in.
*/
#define SL_ATTRIBUTE_SECTION(X) __attribute__ ((section(X)))
/** @brief A macro for notifying the compiler of an intended
* switch case fallthrough. */
#if __GNUC__ >= 7
#define SL_FALLTHROUGH __attribute__ ((fallthrough));
#else
#define SL_FALLTHROUGH
#endif
/** @brief A macro for notifying the compiler to ignore type limit check. */
#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
#define SL_IGNORE_TYPE_LIMIT_BEGIN \
_Pragma("GCC diagnostic push") \
_Pragma("GCC diagnostic ignored \"-Wtype-limits\"")
#define SL_IGNORE_TYPE_LIMIT_END \
_Pragma("GCC diagnostic pop")
#else
#define SL_IGNORE_TYPE_LIMIT_BEGIN
#define SL_IGNORE_TYPE_LIMIT_END ///< A MACRO to notify the compiler, limit END.
#endif
#endif // !defined(__GNUC__)
/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
/** @brief
* Macro for marking deprecated functions
*
* @details
* SL_DEPRECATED_API_SDK_<RELEASE> is used to mark functions that are
* deprecated and should not be used from a given version of the SDK.
* The accompanying SL_SUPPRESS_DEPRECATION_WARNINGS_SDK_<RELEASE>
* define can be set to suppress warnings generated when using
* deprecated APIs.
*/
#ifdef SL_SUPPRESS_DEPRECATION_WARNINGS_SDK_3_0
#define SL_DEPRECATED_API_SDK_3_0
#else
#define SL_DEPRECATED_API_SDK_3_0 __attribute__ ((deprecated))
#endif
#ifdef SL_SUPPRESS_DEPRECATION_WARNINGS_SDK_3_2
#define SL_DEPRECATED_API_SDK_3_2
#else
#define SL_DEPRECATED_API_SDK_3_2 __attribute__ ((deprecated))
#endif
#ifdef SL_SUPPRESS_DEPRECATION_WARNINGS_SDK_3_3
#define SL_DEPRECATED_API_SDK_3_3
#else
#define SL_DEPRECATED_API_SDK_3_3 __attribute__ ((deprecated))
#endif
#ifdef SL_SUPPRESS_DEPRECATION_WARNINGS_SDK_4_1
#define SL_DEPRECATED_API_SDK_4_1
#else
#define SL_DEPRECATED_API_SDK_4_1 __attribute__ ((deprecated))
#endif
#ifdef SL_SUPPRESS_DEPRECATION_WARNINGS_SDK_4_2
#define SL_DEPRECATED_API_SDK_4_2
#else
#define SL_DEPRECATED_API_SDK_4_2 __attribute__ ((deprecated))
#endif
#ifdef SL_SUPPRESS_DEPRECATION_WARNINGS_SDK_4_4
#define SL_DEPRECATED_API_SDK_4_4
#else
#define SL_DEPRECATED_API_SDK_4_4 __attribute__ ((deprecated))
#endif
#ifdef SL_SUPPRESS_DEPRECATION_WARNINGS_SDK_2024_6
#define SL_DEPRECATED_API_SDK_2024_6
#else
#define SL_DEPRECATED_API_SDK_2024_6 __attribute__ ((deprecated))
#endif
/** @endcond */
/***************************************************************************//**
* @brief
* Count trailing number of zeros. Use CLZ instruction if available.
*
* @param[in] value
* Data value to check for number of trailing zero bits.
*
* @return
* A number of trailing zeros in value.
******************************************************************************/
__STATIC_INLINE uint32_t SL_CTZ(uint32_t value)
{
#if defined(__CORTEX_M) && (__CORTEX_M >= 3U)
return __CLZ(__RBIT(value));
#else
uint32_t zeros;
for (zeros = 0; (zeros < 32) && ((value & 0x1) == 0); zeros++, value >>= 1) {
;
}
return zeros;
#endif
}
/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
/* Deprecated function. New code should use @ref SL_CTZ. */
__STATIC_INLINE uint32_t EFM32_CTZ(uint32_t value)
{
return SL_CTZ(value);
}
/** @endcond */
/***************************************************************************//**
* @brief
* Reverse the bits. Use the RBIT instruction if available, else process.
*
* @param[in] value
* Data value to reverse.
*
* @return
* A reversed value.
******************************************************************************/
__STATIC_INLINE uint32_t SL_RBIT(uint32_t value)
{
uint32_t result;
#if defined(__CORTEX_M) && (__CORTEX_M >= 0x03U)
result = __RBIT(value);
#else
int32_t s = 4 * 8 - 1;
result = value;
for (value >>= 1U; value != 0U; value >>= 1U) {
result <<= 1U;
result |= value & 1U;
s--;
}
result <<= s;
#endif
return result;
}
/***************************************************************************//**
* @brief
* Reverse the bits. Use the RBIT instruction if available, else process.
*
* @param[in] value
* 16-bit data value to reverse.
*
* @return
* A 16-bit reversed value.
******************************************************************************/
__STATIC_INLINE uint16_t SL_RBIT16(uint16_t value)
{
return (uint16_t)(SL_RBIT(value) >> 16);
}
/***************************************************************************//**
* @brief
* Reverse the bits. Use the RBIT instruction if available, else process.
*
* @param[in] value
* 8-bit data value to reverse.
*
* @return
* A 8-bit reversed value.
******************************************************************************/
__STATIC_INLINE uint8_t SL_RBIT8(uint8_t value)
{
return (uint8_t)(SL_RBIT(value) >> 24);
}
/***************************************************************************//**
* @brief
* Convert logarithm of 2 to division factor.
*
* @param[in] log2
* Logarithm of 2.
*
* @return
* Dividend.
******************************************************************************/
__STATIC_INLINE uint32_t SL_Log2ToDiv(uint32_t log2)
{
EFM_ASSERT(log2 < 32U);
return 1UL << log2;
}
/***************************************************************************//**
* @brief
* Count the number of bits that are set to 1 in a 32-bit bitfield.
*
* @param[in] bitfield
* 32-bit bitfield.
*
* @return
* The number of bits that are set to 1 in the bitfield.
******************************************************************************/
__STATIC_INLINE uint32_t SL_POPCOUNT32(uint32_t bitfield)
{
bitfield = bitfield - ((bitfield >> 1) & 0x55555555);
bitfield = (bitfield & 0x33333333) + ((bitfield >> 2) & 0x33333333);
bitfield = (bitfield + (bitfield >> 4)) & 0x0F0F0F0F;
return (bitfield * 0x01010101) >> 24;
}
/** @} (end addtogroup common) */
#ifdef __cplusplus
}
#endif
#endif /* SL_COMMON_H */

View File

@@ -0,0 +1,210 @@
/***************************************************************************//**
* @file
* @brief Silabs Compiler definitions.
*******************************************************************************
* # License
* <b>Copyright 2022 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* 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.
*
******************************************************************************/
#ifndef SL_COMPILER_H
#define SL_COMPILER_H
/***************************************************************************//**
* @addtogroup compiler Compiler definitions
* @brief Compiler definitions
* @{
******************************************************************************/
#ifdef __cplusplus
extern "C" {
#endif
#if defined (__GNUC__)
// Fallback for __has_builtin.
#ifndef __has_builtin
#define __has_builtin(x) (0)
#endif
// Compiler specific defines.
#ifndef __ASM
#define __ASM __asm
#endif
#ifndef __INLINE
#define __INLINE inline
#endif
#ifndef __STATIC_INLINE
#define __STATIC_INLINE static inline
#endif
#ifndef __STATIC_FORCEINLINE
#define __STATIC_FORCEINLINE __attribute__((always_inline)) static inline
#endif
#ifndef __NO_RETURN
#define __NO_RETURN __attribute__((__noreturn__))
#endif
#ifndef __USED
#define __USED __attribute__((used))
#endif
#ifndef __WEAK
#define __WEAK __attribute__((weak))
#endif
#ifndef __PACKED
#define __PACKED __attribute__((packed, aligned(1)))
#endif
#ifndef __PACKED_STRUCT
#define __PACKED_STRUCT struct __attribute__((packed, aligned(1)))
#endif
#ifndef __PACKED_UNION
#define __PACKED_UNION union __attribute__((packed, aligned(1)))
#endif
#ifndef __ALIGNED
#define __ALIGNED(x) __attribute__((aligned(x)))
#endif
#ifndef __RESTRICT
#define __RESTRICT __restrict
#endif
#elif defined(__IAR_SYSTEMS_ICC__)
#pragma system_include
#if (__VER__ >= 8000000)
#define __ICCARM_V8 1
#else
#define __ICCARM_V8 0
#endif
#ifndef __ALIGNED
#if __ICCARM_V8
#define __ALIGNED(x) __attribute__((aligned(x)))
#elif (__VER__ >= 7080000)
/* Needs IAR language extensions */
#define __ALIGNED(x) __attribute__((aligned(x)))
#else
#warning No compiler specific solution for __ALIGNED.__ALIGNED is ignored.
#define __ALIGNED(x)
#endif
#endif
#ifndef __ASM
#define __ASM __asm
#endif
#ifndef __INLINE
#define __INLINE inline
#endif
#ifndef __NO_RETURN
#if __ICCARM_V8
#define __NO_RETURN __attribute__((__noreturn__))
#else
#define __NO_RETURN _Pragma("object_attribute=__noreturn")
#endif
#endif
#ifndef __PACKED
#if __ICCARM_V8
#define __PACKED __attribute__((packed, aligned(1)))
#else
/* Needs IAR language extensions */
#define __PACKED __packed
#endif
#endif
#ifndef __PACKED_STRUCT
#if __ICCARM_V8
#define __PACKED_STRUCT struct __attribute__((packed, aligned(1)))
#else
/* Needs IAR language extensions */
#define __PACKED_STRUCT __packed struct
#endif
#endif
#ifndef __PACKED_UNION
#if __ICCARM_V8
#define __PACKED_UNION union __attribute__((packed, aligned(1)))
#else
/* Needs IAR language extensions */
#define __PACKED_UNION __packed union
#endif
#endif
#ifndef __RESTRICT
#define __RESTRICT restrict
#endif
#ifndef __STATIC_INLINE
#define __STATIC_INLINE static inline
#endif
#ifndef __FORCEINLINE
#define __FORCEINLINE _Pragma("inline=forced")
#endif
#ifndef __STATIC_FORCEINLINE
#define __STATIC_FORCEINLINE __FORCEINLINE __STATIC_INLINE
#endif
#ifndef __USED
#if __ICCARM_V8
#define __USED __attribute__((used))
#else
#define __USED _Pragma("__root")
#endif
#endif
#ifndef __WEAK
#if __ICCARM_V8
#define __WEAK __attribute__((weak))
#else
#define __WEAK _Pragma("__weak")
#endif
#endif
#else
#error "Unknown compiler."
#endif
// IO definitions (access restrictions to peripheral registers).
#ifdef __cplusplus
#define __I volatile ///< Defines 'read only' permissions
#else
#define __I volatile const ///< Defines 'read only' permissions
#endif
#define __O volatile ///< Defines 'write only' permissions
#define __IO volatile ///< Defines 'read / write' permissions
// The following defines should be used for structure members.
#define __IM volatile const ///< Defines 'read only' structure member permissions
#define __OM volatile ///< Defines 'write only' structure member permissions
#define __IOM volatile ///< Defines 'read / write' structure member permissions
#ifdef __cplusplus
}
#endif
/** @} (end group compiler) */
#endif // SL_COMPILER_H

View File

@@ -0,0 +1,499 @@
/***************************************************************************//**
* @file
* @brief Core API
*******************************************************************************
* # License
* <b>Copyright 2023 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* 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.
*
******************************************************************************/
#ifndef SL_CORE_H
#define SL_CORE_H
#include <stdint.h>
#include <stdbool.h>
#include "sl_code_classification.h"
#ifdef __cplusplus
extern "C" {
#endif
/***************************************************************************//**
* @addtogroup sl_core Core
*
* @section sl_core_intro Introduction
*
* The core abstraction API provides high-level, device agnostic, control of
* core peripherals, most notably the ability to execute code in sections with
* varying levels of interrupt masking.
*
* This module provides support for two types of critical sections, each
* with different interrupt masking capabilities.
*
* @li <b>CRITICAL section</b>: Inside a critical section, all interrupts are
* masked (except for core exception handlers).
* @li <b>ATOMIC section</b>: Inside an atomic section, interrupts with a
* priority less than the configurable @ref SL_CORE_BASE_PRIORITY_LEVEL
* value will be masked.
*
* @section sl_core_conf Compile-time Configuration
*
* The following #define is used to configure sl_core:
* @code{.c}
* // Enables debug methods to measure the time spent in critical sections.
* #define SL_CORE_DEBUG_INTERRUPTS_MASKED_TIMING 0
* @endcode
*
* @section sl_core_macro_api Macro API
*
* The core abstraction API has macros to facilitate executing code in
* ATOMIC and CRITICAL sections.
*
* @ref CORE_DECLARE_IRQ_STATE, @ref CORE_ENTER_ATOMIC() and
* @ref CORE_EXIT_ATOMIC() can be used together to implement an ATOMIC section.
* @code{.c}
* {
* CORE_DECLARE_IRQ_STATE; // Storage for saving IRQ state prior to
* // atomic section entry.
*
* CORE_ENTER_ATOMIC(); // Enter atomic section.
*
* ...
* ... your code goes here ...
* ...
*
* CORE_EXIT_ATOMIC(); // Exit atomic section, IRQ state is restored.
* }
* @endcode
*
* @ref CORE_ATOMIC_SECTION(yourcode) is aconcatenation of all three of the
* macros above.
* @code{.c}
* {
* CORE_ATOMIC_SECTION(
* ...
* ... your code goes here ...
* ...
* )
* }
* @endcode
*
* The following macros implement CRITICAL sections in a similar fashion as
* described above for ATOMIC sections:
* <li>@ref CORE_DECLARE_IRQ_STATE</li>
* <li>@ref CORE_ENTER_CRITICAL()</li>
* <li>@ref CORE_EXIT_CRITICAL()</li>
* <li>@ref CORE_CRITICAL_SECTION(yourcode)</li>
*
* @section sl_core_reimplementation API Reimplementation
*
* Most of the functions in the API are implemented as weak functions. This means
* that it is easy to reimplement when special needs arise. Shown below is a
* reimplementation of CRITICAL sections suitable if FreeRTOS OS is used:
* @code{.c}
* CORE_irqState_t CORE_EnterCritical(void)
* {
* vPortEnterCritical();
* return 0;
* }
*
* void CORE_ExitCritical(CORE_irqState_t irqState)
* {
* (void)irqState;
* vPortExitCritical();
* }
* @endcode
* Also note that CORE_Enter/ExitCritical() are not implemented as inline
* functions. As a result, reimplementations will be possible even when original
* implementations are inside a linked library.
*
* Some RTOSes must be notified on interrupt handler entry and exit. Macros
* @ref CORE_INTERRUPT_ENTRY() and @ref CORE_INTERRUPT_EXIT() are suitable
* placeholders for inserting such code. Insert these macros in all your
* interrupt handlers and then override the default macro implementations.
* This is an example if uC/OS is used:
* @code{.c}
* // In emlib_config.h:
*
* #define CORE_INTERRUPT_ENTRY() OSIntEnter()
* #define CORE_INTERRUPT_EXIT() OSIntExit()
* @endcode
*
* @section sl_core_max_timing Maximum Interrupt Disabled Time
*
* The maximum time spent (in cycles) in critical and atomic sections can be
* measured for performance and interrupt latency analysis.
* To enable the timings, use the SL_CORE_ENABLE_INTERRUPT_DISABLED_TIMING
* configuration option. When enabled, the functions
* @ref CORE_get_max_time_critical_section() and
* @ref CORE_get_max_time_atomic_section()
* can be used to get the max timings since startup.
*
* @section sl_core_porting Porting from em_int
*
* Existing code using INT_Enable() and INT_Disable() must be ported to the
* sl_core API. While em_int used, a global counter to store the interrupt state,
* sl_core uses a local variable. Any usage of INT_Disable(), therefore, needs to
* be replaced with a declaration of the interrupt state variable before entering
* the critical section.
*
* Since the state variable is in local scope, the critical section exit
* needs to occur within the scope of the variable. If multiple nested critical
* sections are used, each needs to have its own state variable in its own scope.
*
* In many cases, completely disabling all interrupts using CRITICAL sections
* might be more heavy-handed than needed. When porting, consider whether
* an ATOMIC section can be used to only disable a subset of the interrupts.
*
* Replacing em_int calls with sl_core function calls:
* @code{.c}
* void func(void)
* {
* // INT_Disable();
* CORE_DECLARE_IRQ_STATE;
* CORE_ENTER_ATOMIC();
* .
* .
* .
* // INT_Enable();
* CORE_EXIT_ATOMIC();
* }
* @endcode
* @{
******************************************************************************/
/*******************************************************************************
***************************** DEFINES *************************************
******************************************************************************/
#if !defined(CORE_ATOMIC_BASE_PRIORITY_LEVEL)
/** The interrupt priority level disabled within ATOMIC regions. Interrupts
* with priority level equal to or lower than this definition will be disabled
* within ATOMIC regions. */
#define CORE_ATOMIC_BASE_PRIORITY_LEVEL 3
#else
#ifndef SL_SUPPRESS_DEPRECATION_WARNINGS_SDK_2024_6
#warning "The CORE_ATOMIC_BASE_PRIORITY_LEVEL configuration is DEPRECATED. In \
later releases, the base priority of atomic sections will be hardcoded to 3 \
and will no longer be configurable. Please consider updating the priorities \
of interrupts in your application to account for this new hardcoded value."
#endif
#endif
/*******************************************************************************
************************ MACRO API ***************************************
******************************************************************************/
/// Allocate storage for PRIMASK or BASEPRI value for use by
/// CORE_ENTER/EXIT_ATOMIC() and CORE_ENTER/EXIT_CRITICAL() macros.
#define CORE_DECLARE_IRQ_STATE CORE_irqState_t irqState
/// CRITICAL style interrupt disable.
#define CORE_CRITICAL_IRQ_DISABLE() CORE_CriticalDisableIrq()
/// CRITICAL style interrupt enable.
#define CORE_CRITICAL_IRQ_ENABLE() CORE_CriticalEnableIrq()
/// Convenience macro for implementing a CRITICAL section.
#define CORE_CRITICAL_SECTION(yourcode) \
{ \
CORE_DECLARE_IRQ_STATE; \
CORE_ENTER_CRITICAL(); \
{ \
yourcode \
} \
CORE_EXIT_CRITICAL(); \
}
/// Enter CRITICAL section. Assumes that a @ref CORE_DECLARE_IRQ_STATE exist in
/// scope.
#define CORE_ENTER_CRITICAL() irqState = CORE_EnterCritical()
/// Exit CRITICAL section. Assumes that a @ref CORE_DECLARE_IRQ_STATE exist in
/// scope.
#define CORE_EXIT_CRITICAL() CORE_ExitCritical(irqState)
/// CRITICAL style yield.
#define CORE_YIELD_CRITICAL() CORE_YieldCritical()
/// ATOMIC style interrupt disable.
#define CORE_ATOMIC_IRQ_DISABLE() CORE_AtomicDisableIrq()
/// ATOMIC style interrupt enable.
#define CORE_ATOMIC_IRQ_ENABLE() CORE_AtomicEnableIrq()
/// Convenience macro for implementing an ATOMIC section.
#define CORE_ATOMIC_SECTION(yourcode) \
{ \
CORE_DECLARE_IRQ_STATE; \
CORE_ENTER_ATOMIC(); \
{ \
yourcode \
} \
CORE_EXIT_ATOMIC(); \
}
/// Enter ATOMIC section. Assumes that a @ref CORE_DECLARE_IRQ_STATE exist in
/// scope.
#define CORE_ENTER_ATOMIC() irqState = CORE_EnterAtomic()
/// Exit ATOMIC section. Assumes that a @ref CORE_DECLARE_IRQ_STATE exist in
/// scope.
#define CORE_EXIT_ATOMIC() CORE_ExitAtomic(irqState)
/// ATOMIC style yield.
#define CORE_YIELD_ATOMIC() CORE_YieldAtomic()
/// Check if IRQ is disabled.
#define CORE_IRQ_DISABLED() CORE_IrqIsDisabled()
/// Check if inside an IRQ handler.
#define CORE_IN_IRQ_CONTEXT() CORE_InIrqContext()
// Reset System.
#define CORE_RESET_SYSTEM() CORE_ResetSystem()
/*******************************************************************************
************************* TYPEDEFS ****************************************
******************************************************************************/
/// Storage for PRIMASK or BASEPRI value.
typedef uint32_t CORE_irqState_t;
/*******************************************************************************
***************************** PROTOTYPES **********************************
******************************************************************************/
/***************************************************************************//**
* @brief
* Disable interrupts.
*
* Disable all interrupts by setting PRIMASK.
* (Fault exception handlers will still be enabled).
******************************************************************************/
SL_CODE_CLASSIFY(SL_CODE_COMPONENT_CORE, SL_CODE_CLASS_TIME_CRITICAL)
void CORE_CriticalDisableIrq(void);
/***************************************************************************//**
* @brief
* Enable interrupts.
*
* Enable interrupts by clearing PRIMASK.
******************************************************************************/
SL_CODE_CLASSIFY(SL_CODE_COMPONENT_CORE, SL_CODE_CLASS_TIME_CRITICAL)
void CORE_CriticalEnableIrq(void);
/***************************************************************************//**
* @brief
* Exit a CRITICAL section.
*
* @param[in] irqState
* The interrupt priority blocking level to restore to PRIMASK when exiting
* the CRITICAL section. This value is usually the one returned by a prior
* call to @ref CORE_EnterCritical().
******************************************************************************/
SL_CODE_CLASSIFY(SL_CODE_COMPONENT_CORE, SL_CODE_CLASS_TIME_CRITICAL)
void CORE_ExitCritical(CORE_irqState_t irqState);
/***************************************************************************//**
* @brief
* Brief interrupt enable/disable sequence to allow handling of
* pending interrupts.
*
* @note
* Usually used within a CRITICAL section.
******************************************************************************/
SL_CODE_CLASSIFY(SL_CODE_COMPONENT_CORE, SL_CODE_CLASS_TIME_CRITICAL)
void CORE_YieldCritical(void);
/***************************************************************************//**
* @brief
* Enter a CRITICAL section.
*
* When a CRITICAL section is entered, all interrupts (except fault handlers)
* are disabled.
*
* @return
* The value of PRIMASK register prior to the CRITICAL section entry.
******************************************************************************/
SL_CODE_CLASSIFY(SL_CODE_COMPONENT_CORE, SL_CODE_CLASS_TIME_CRITICAL)
CORE_irqState_t CORE_EnterCritical(void);
/***************************************************************************//**
* @brief
* Disable interrupts.
*
* Disable interrupts with a priority lower or equal to
* @ref CORE_ATOMIC_BASE_PRIORITY_LEVEL. Sets core BASEPRI register
* to CORE_ATOMIC_BASE_PRIORITY_LEVEL.
*
* @note
* If @ref CORE_ATOMIC_METHOD is @ref CORE_ATOMIC_METHOD_PRIMASK, this
* function is identical to @ref CORE_CriticalDisableIrq().
******************************************************************************/
SL_CODE_CLASSIFY(SL_CODE_COMPONENT_CORE, SL_CODE_CLASS_TIME_CRITICAL)
void CORE_AtomicDisableIrq(void);
/***************************************************************************//**
* @brief
* Enable interrupts.
*
* Enable interrupts by setting core BASEPRI register to 0.
*
* @note
* If @ref CORE_ATOMIC_METHOD is @ref CORE_ATOMIC_METHOD_BASEPRI and PRIMASK
* is set (CPU is inside a CRITICAL section), interrupts will still be
* disabled after calling this function.
*
* @note
* If @ref CORE_ATOMIC_METHOD is @ref CORE_ATOMIC_METHOD_PRIMASK, this
* function is identical to @ref CORE_CriticalEnableIrq().
******************************************************************************/
SL_CODE_CLASSIFY(SL_CODE_COMPONENT_CORE, SL_CODE_CLASS_TIME_CRITICAL)
void CORE_AtomicEnableIrq(void);
/***************************************************************************//**
* @brief
* Exit an ATOMIC section.
*
* @param[in] irqState
* The interrupt priority blocking level to restore to BASEPRI when exiting
* the ATOMIC section. This value is usually the one returned by a prior
* call to @ref CORE_EnterAtomic().
*
* @note
* If @ref CORE_ATOMIC_METHOD is set to @ref CORE_ATOMIC_METHOD_PRIMASK, this
* function is identical to @ref CORE_ExitCritical().
******************************************************************************/
SL_CODE_CLASSIFY(SL_CODE_COMPONENT_CORE, SL_CODE_CLASS_TIME_CRITICAL)
void CORE_ExitAtomic(CORE_irqState_t irqState);
/***************************************************************************//**
* @brief
* Brief interrupt enable/disable sequence to allow handling of
* pending interrupts.
*
* @note
* Usually used within an ATOMIC section.
*
* @note
* If @ref CORE_ATOMIC_METHOD is @ref CORE_ATOMIC_METHOD_PRIMASK, this
* function is identical to @ref CORE_YieldCritical().
******************************************************************************/
SL_CODE_CLASSIFY(SL_CODE_COMPONENT_CORE, SL_CODE_CLASS_TIME_CRITICAL)
void CORE_YieldAtomic(void);
/***************************************************************************//**
* @brief
* Enter an ATOMIC section.
*
* When an ATOMIC section is entered, interrupts with priority lower or equal
* to @ref CORE_ATOMIC_BASE_PRIORITY_LEVEL are disabled.
*
* @note
* If @ref CORE_ATOMIC_METHOD is @ref CORE_ATOMIC_METHOD_PRIMASK, this
* function is identical to @ref CORE_EnterCritical().
*
* @return
* The value of BASEPRI register prior to ATOMIC section entry.
******************************************************************************/
SL_CODE_CLASSIFY(SL_CODE_COMPONENT_CORE, SL_CODE_CLASS_TIME_CRITICAL)
CORE_irqState_t CORE_EnterAtomic(void);
/***************************************************************************//**
* @brief
* Check whether the current CPU operation mode is handler mode.
*
* @return
* True if the CPU is in handler mode (currently executing an interrupt handler).
* @n False if the CPU is in thread mode.
******************************************************************************/
SL_CODE_CLASSIFY(SL_CODE_COMPONENT_CORE, SL_CODE_CLASS_TIME_CRITICAL)
bool CORE_InIrqContext(void);
/***************************************************************************//**
* @brief
* Check if interrupts are disabled.
*
* @return
* True if interrupts are disabled.
******************************************************************************/
SL_CODE_CLASSIFY(SL_CODE_COMPONENT_CORE, SL_CODE_CLASS_TIME_CRITICAL)
bool CORE_IrqIsDisabled(void);
/***************************************************************************//**
* @brief
* Returns the max time spent in critical section.
*
* @return
* The max time spent in critical section.
*
* @note SL_CORE_DEBUG_INTERRUPTS_MASKED_TIMING must be enabled.
******************************************************************************/
SL_CODE_CLASSIFY(SL_CODE_COMPONENT_CORE, SL_CODE_CLASS_TIME_CRITICAL)
uint32_t CORE_get_max_time_critical_section(void);
/***************************************************************************//**
* @brief
* Returns the max time spent in atomic section.
*
* @return
* The max time spent in atomic section.
*
* @note SL_CORE_DEBUG_INTERRUPTS_MASKED_TIMING must be enabled.
******************************************************************************/
SL_CODE_CLASSIFY(SL_CODE_COMPONENT_CORE, SL_CODE_CLASS_TIME_CRITICAL)
uint32_t CORE_get_max_time_atomic_section(void);
/***************************************************************************//**
* @brief
* Clears the max time spent in atomic section.
*
* @note SL_CORE_DEBUG_INTERRUPTS_MASKED_TIMING must be enabled.
******************************************************************************/
SL_CODE_CLASSIFY(SL_CODE_COMPONENT_CORE, SL_CODE_CLASS_TIME_CRITICAL)
void CORE_clear_max_time_critical_section(void);
/***************************************************************************//**
* @brief
* Clears the max time spent in atomic section.
*
* @note SL_CORE_DEBUG_INTERRUPTS_MASKED_TIMING must be enabled.
******************************************************************************/
SL_CODE_CLASSIFY(SL_CODE_COMPONENT_CORE, SL_CODE_CLASS_TIME_CRITICAL)
void CORE_clear_max_time_atomic_section(void);
/***************************************************************************//**
* @brief
* Reset chip routine.
******************************************************************************/
void CORE_ResetSystem(void);
/** @} (end addtogroup sl_core) */
#ifdef __cplusplus
}
#endif
#endif /* SL_CORE_H */

View File

@@ -0,0 +1,66 @@
/*******************************************************************************
* @file
* @brief SL_ENUM Implementation
*******************************************************************************
* # License
* <b>Copyright 2019 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* 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.
*
******************************************************************************/
#ifndef SL_ENUM_H
#define SL_ENUM_H
/*******************************************************************************
* @addtogroup enum Enumerations
* @brief Enumerations with stable binary representation
* @details
* Silicon Labs libraries do not use enumerations because the ARM EABI leaves
* their size ambiguous, which causes problems if the application is built
* with different flags than the library. Instead, uint8_t typedefs
* are used in compiled code for all enumerations. For documentation purposes,
* this is converted to an actual enumeration in documentation.
* @{
******************************************************************************/
#ifdef DOXYGEN
/// Enumeration mapped to uint8_t
#define SL_ENUM(name) enum name
/// Enumeration mapped to arbitrary type
#define SL_ENUM_GENERIC(name, type) enum name
#else
// NOTE: The following macros might cause MISRA warnings because
// Macro parameters need to be enclosed in parentheses.
// However, it is not possible in C to enclose declaration
// identifiers in parentheses. For example:
// typedef uint8_t (some_identifier);
// is not syntactically correct in the C language (C99).
#define SL_ENUM(name) typedef uint8_t name; enum name##_enum
#define SL_ENUM_GENERIC(name, type) typedef type name; enum name##_enum
// For debugging, use the following define to turn this back into a proper enumeration
// #define SL_ENUM(name) typedef enum name##_enum name; enum name##_enum
#endif
/** @} end enum */
#endif // SL_ENUM_H

View File

@@ -0,0 +1,173 @@
/*******************************************************************************
* @file
* @brief Single Link List.
*******************************************************************************
* # License
* <b>Copyright 2019 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* 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.
*
******************************************************************************/
#ifndef SL_SLIST_H
#define SL_SLIST_H
#include <stdbool.h>
#include <stdlib.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/*******************************************************************************
* @addtogroup slist Singly-Linked List
* @brief Singly-linked List module provides APIs to handle singly-linked list
* operations such as insert, push, pop, push back, sort and remove.
*
* @note The pop operation follows FIFO method.
* @n @section slist_usage Singly-Linked List module Usage
* @{
******************************************************************************/
/// List node type
typedef struct sl_slist_node sl_slist_node_t;
/// List node
struct sl_slist_node {
sl_slist_node_t *node; ///< List node
};
#ifndef DOXYGEN
#define container_of(ptr, type, member) (type *)((uintptr_t)(ptr) - ((uintptr_t)(&((type *)0)->member)))
#define SL_SLIST_ENTRY container_of
#define SL_SLIST_FOR_EACH(list_head, iterator) for ((iterator) = (list_head); (iterator) != NULL; (iterator) = (iterator)->node)
#define SL_SLIST_FOR_EACH_ENTRY(list_head, entry, type, member) for ( (entry) = SL_SLIST_ENTRY(list_head, type, member); \
(type *)(entry) != SL_SLIST_ENTRY(NULL, type, member); \
(entry) = SL_SLIST_ENTRY((entry)->member.node, type, member))
#endif
// -----------------------------------------------------------------------------
// Prototypes
/*******************************************************************************
* Initialize a singly-linked list.
*
* @param head Pointer to pointer of head element of list.
******************************************************************************/
void sl_slist_init(sl_slist_node_t **head);
/*******************************************************************************
* Add given item at beginning of the list.
*
* @param head Pointer to pointer of head element of the list.
*
* @param item Pointer to an item to add.
******************************************************************************/
void sl_slist_push(sl_slist_node_t **head,
sl_slist_node_t *item);
/*******************************************************************************
* Add item at the end of the list.
*
* @param head Pointer to the pointer of a head element of the list.
*
* @param item Pointer to the item to add.
******************************************************************************/
void sl_slist_push_back(sl_slist_node_t **head,
sl_slist_node_t *item);
/*******************************************************************************
* Remove and return the first element of the list.
*
* @param head Pointer to he pointer of the head element of the list.
*
* @return Pointer to item that was at top of the list.
******************************************************************************/
sl_slist_node_t *sl_slist_pop(sl_slist_node_t **head);
/*******************************************************************************
* Insert an item after the given item.
*
* @param item Pointer to an item to add.
*
* @param pos Pointer to an item after which the item to add will be inserted.
******************************************************************************/
void sl_slist_insert(sl_slist_node_t *item,
sl_slist_node_t *pos);
/*******************************************************************************
* Join two lists together.
*
* @param head_list_1 Pointer to the pointer of a head element of the list.
*
* @param head_list_2 Pointer to the pointer of a head element of the list
* to be appended. After the call, this pointer will be
* invalidated (set to NULL).
******************************************************************************/
void sl_slist_join(sl_slist_node_t **head_list_1,
sl_slist_node_t **head_list_2);
/*******************************************************************************
* Remove an item from the list.
*
* @param head Pointer to pointer of the head element of list.
*
* @param item Pointer to the item to remove.
******************************************************************************/
void sl_slist_remove(sl_slist_node_t **head,
sl_slist_node_t *item);
/*******************************************************************************
* Sort list items.
*
* @param head Pointer to the pointer of the head element of the list.
*
* @param cmp_fnct Pointer to function to use for sorting the list.
* item_l Pointer to left item.
* item_r Pointer to right item.
* Returns whether the two items are ordered (true) or not (false).
******************************************************************************/
void sl_slist_sort(sl_slist_node_t **head,
bool (*cmp_fnct)(sl_slist_node_t *item_l,
sl_slist_node_t *item_r));
/*******************************************************************************
* Checks if the list is empty.
*
* @param head Pointer to the head element of the list.
******************************************************************************/
static inline bool sl_slist_is_empty(sl_slist_node_t *head)
{
return head == NULL;
}
/** @} (end addtogroup slist) */
#ifdef __cplusplus
}
#endif
#endif /* SL_SLIST_H */

View File

@@ -0,0 +1,526 @@
/*******************************************************************************
* @file
* @brief SL Status Codes.
*******************************************************************************
* # License
* <b>Copyright 2019 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* 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.
*
******************************************************************************/
#ifndef SL_STATUS_H
#define SL_STATUS_H
#include <stdint.h>
/*******************************************************************************
* @addtogroup status Status Codes
* @details Status Codes contains error and status code definitions used by
* Simplicity SDK software components and stacks. This module also
* provides routines to read the string linked with the error and
* status codes.
* @{
******************************************************************************/
// -----------------------------------------------------------------------------
// Space Defines
#define SL_STATUS_SPACE_MASK ((sl_status_t)0xFF00) ///< sl status space mask.
#define SL_STATUS_GENERIC_SPACE ((sl_status_t)0x0000) ///< sl status generic space.
#define SL_STATUS_PLATFORM_1_SPACE ((sl_status_t)0x0100) ///< sl status platform 1 space.
#define SL_STATUS_PLATFORM_2_SPACE ((sl_status_t)0x0200) ///< sl status platform 2 space.
#define SL_STATUS_HARDWARE_SPACE ((sl_status_t)0x0300) ///< sl status hardware space.
#define SL_STATUS_BLUETOOTH_SPACE ((sl_status_t)0x0400) ///< sl status bluetooth space.
#define SL_STATUS_BLUETOOTH_MESH_SPACE ((sl_status_t)0x0500) ///< sl status bluetooth mesh space.
#define SL_STATUS_CAN_CANOPEN_SPACE ((sl_status_t)0x0600) ///< sl status can canopen space.
#define SL_STATUS_CONNECT_SPACE ((sl_status_t)0x0700) ///< sl status connect space.
#define SL_STATUS_NET_SUITE_SPACE ((sl_status_t)0x0800) ///< sl status net suite space.
#define SL_STATUS_THREAD_SPACE ((sl_status_t)0x0900) ///< sl status thread space.
#define SL_STATUS_USB_SPACE ((sl_status_t)0x0A00) ///< sl status usb space.
#define SL_STATUS_WIFI_SPACE ((sl_status_t)0x0B00) ///< sl status wifi space.
#define SL_STATUS_ZIGBEE_SPACE ((sl_status_t)0x0C00) ///< sl status zigbee space.
#define SL_STATUS_Z_WAVE_SPACE ((sl_status_t)0x0D00) ///< sl status z wave space.
#define SL_STATUS_GECKO_OS_1_SPACE ((sl_status_t)0x0E00) ///< sl status gecko os 1 space.
#define SL_STATUS_GECKO_OS_2_SPACE ((sl_status_t)0x0F00) ///< sl status gecko os 2 space.
#define SL_STATUS_BLUETOOTH_CTRL_SPACE ((sl_status_t)0x1000) ///< sl status bluetooth ctrl space.
#define SL_STATUS_BLUETOOTH_ATT_SPACE ((sl_status_t)0x1100) ///< sl status bluetooth att space.
#define SL_STATUS_BLUETOOTH_SMP_SPACE ((sl_status_t)0x1200) ///< sl status bluetooth mesh foundation space.
#define SL_STATUS_BLUETOOTH_MESH_FOUNDATION_SPACE ((sl_status_t)0x1300) ///< sl status bluetooth mesh foundation space.
#define SL_STATUS_WISUN_SPACE ((sl_status_t)0x1400) ///< sl status wisun space.
#define SL_STATUS_COMPUTE_SPACE ((sl_status_t)0x1500) ///< sl status compute space.
// -----------------------------------------------------------------------------
// Status Defines
// -----------------------------------------------------------------------------
// Generic Errors
#define SL_STATUS_OK ((sl_status_t)0x0000) ///< No error.
#define SL_STATUS_FAIL ((sl_status_t)0x0001) ///< Generic error.
// State Errors
#define SL_STATUS_INVALID_STATE ((sl_status_t)0x0002) ///< Generic invalid state error.
#define SL_STATUS_NOT_READY ((sl_status_t)0x0003) ///< Module is not ready for requested operation.
#define SL_STATUS_BUSY ((sl_status_t)0x0004) ///< Module is busy and cannot carry out requested operation.
#define SL_STATUS_IN_PROGRESS ((sl_status_t)0x0005) ///< Operation is in progress and not yet complete (pass or fail).
#define SL_STATUS_ABORT ((sl_status_t)0x0006) ///< Operation aborted.
#define SL_STATUS_TIMEOUT ((sl_status_t)0x0007) ///< Operation timed out.
#define SL_STATUS_PERMISSION ((sl_status_t)0x0008) ///< Operation not allowed per permissions.
#define SL_STATUS_WOULD_BLOCK ((sl_status_t)0x0009) ///< Non-blocking operation would block.
#define SL_STATUS_IDLE ((sl_status_t)0x000A) ///< Operation/module is Idle, cannot carry requested operation.
#define SL_STATUS_IS_WAITING ((sl_status_t)0x000B) ///< Operation cannot be done while construct is waiting.
#define SL_STATUS_NONE_WAITING ((sl_status_t)0x000C) ///< No task/construct waiting/pending for that action/event.
#define SL_STATUS_SUSPENDED ((sl_status_t)0x000D) ///< Operation cannot be done while construct is suspended.
#define SL_STATUS_NOT_AVAILABLE ((sl_status_t)0x000E) ///< Feature not available due to software configuration.
#define SL_STATUS_NOT_SUPPORTED ((sl_status_t)0x000F) ///< Feature not supported.
#define SL_STATUS_INITIALIZATION ((sl_status_t)0x0010) ///< Initialization failed.
#define SL_STATUS_NOT_INITIALIZED ((sl_status_t)0x0011) ///< Module has not been initialized.
#define SL_STATUS_ALREADY_INITIALIZED ((sl_status_t)0x0012) ///< Module has already been initialized.
#define SL_STATUS_DELETED ((sl_status_t)0x0013) ///< Object/construct has been deleted.
#define SL_STATUS_ISR ((sl_status_t)0x0014) ///< Illegal call from ISR.
#define SL_STATUS_NETWORK_UP ((sl_status_t)0x0015) ///< Illegal call because network is up.
#define SL_STATUS_NETWORK_DOWN ((sl_status_t)0x0016) ///< Illegal call because network is down.
#define SL_STATUS_NOT_JOINED ((sl_status_t)0x0017) ///< Failure due to not being joined in a network.
#define SL_STATUS_NO_BEACONS ((sl_status_t)0x0018) ///< Invalid operation as there are no beacons.
// Allocation/ownership Errors
#define SL_STATUS_ALLOCATION_FAILED ((sl_status_t)0x0019) ///< Generic allocation error.
#define SL_STATUS_NO_MORE_RESOURCE ((sl_status_t)0x001A) ///< No more resource available to perform the operation.
#define SL_STATUS_EMPTY ((sl_status_t)0x001B) ///< Item/list/queue is empty.
#define SL_STATUS_FULL ((sl_status_t)0x001C) ///< Item/list/queue is full.
#define SL_STATUS_WOULD_OVERFLOW ((sl_status_t)0x001D) ///< Item would overflow.
#define SL_STATUS_HAS_OVERFLOWED ((sl_status_t)0x001E) ///< Item/list/queue has been overflowed.
#define SL_STATUS_OWNERSHIP ((sl_status_t)0x001F) ///< Generic ownership error.
#define SL_STATUS_IS_OWNER ((sl_status_t)0x0020) ///< Already/still owning resource.
// Invalid Parameters Errors
#define SL_STATUS_INVALID_PARAMETER ((sl_status_t)0x0021) ///< Generic invalid argument or consequence of invalid argument.
#define SL_STATUS_NULL_POINTER ((sl_status_t)0x0022) ///< Invalid null pointer received as argument.
#define SL_STATUS_INVALID_CONFIGURATION ((sl_status_t)0x0023) ///< Invalid configuration provided.
#define SL_STATUS_INVALID_MODE ((sl_status_t)0x0024) ///< Invalid mode.
#define SL_STATUS_INVALID_HANDLE ((sl_status_t)0x0025) ///< Invalid handle.
#define SL_STATUS_INVALID_TYPE ((sl_status_t)0x0026) ///< Invalid type for operation.
#define SL_STATUS_INVALID_INDEX ((sl_status_t)0x0027) ///< Invalid index.
#define SL_STATUS_INVALID_RANGE ((sl_status_t)0x0028) ///< Invalid range.
#define SL_STATUS_INVALID_KEY ((sl_status_t)0x0029) ///< Invalid key.
#define SL_STATUS_INVALID_CREDENTIALS ((sl_status_t)0x002A) ///< Invalid credentials.
#define SL_STATUS_INVALID_COUNT ((sl_status_t)0x002B) ///< Invalid count.
#define SL_STATUS_INVALID_SIGNATURE ((sl_status_t)0x002C) ///< Invalid signature / verification failed.
#define SL_STATUS_NOT_FOUND ((sl_status_t)0x002D) ///< Item could not be found.
#define SL_STATUS_ALREADY_EXISTS ((sl_status_t)0x002E) ///< Item already exists.
// IO/Communication Errors
#define SL_STATUS_IO ((sl_status_t)0x002F) ///< Generic I/O failure.
#define SL_STATUS_IO_TIMEOUT ((sl_status_t)0x0030) ///< I/O failure due to timeout.
#define SL_STATUS_TRANSMIT ((sl_status_t)0x0031) ///< Generic transmission error.
#define SL_STATUS_TRANSMIT_UNDERFLOW ((sl_status_t)0x0032) ///< Transmit underflowed.
#define SL_STATUS_TRANSMIT_INCOMPLETE ((sl_status_t)0x0033) ///< Transmit is incomplete.
#define SL_STATUS_TRANSMIT_BUSY ((sl_status_t)0x0034) ///< Transmit is busy.
#define SL_STATUS_RECEIVE ((sl_status_t)0x0035) ///< Generic reception error.
#define SL_STATUS_OBJECT_READ ((sl_status_t)0x0036) ///< Failed to read on/via given object.
#define SL_STATUS_OBJECT_WRITE ((sl_status_t)0x0037) ///< Failed to write on/via given object.
#define SL_STATUS_MESSAGE_TOO_LONG ((sl_status_t)0x0038) ///< Message is too long.
// EEPROM/Flash Errors
#define SL_STATUS_EEPROM_MFG_VERSION_MISMATCH ((sl_status_t)0x0039) ///< EEPROM MFG version mismatch.
#define SL_STATUS_EEPROM_STACK_VERSION_MISMATCH ((sl_status_t)0x003A) ///< EEPROM Stack version mismatch.
#define SL_STATUS_FLASH_WRITE_INHIBITED ((sl_status_t)0x003B) ///< Flash write is inhibited.
#define SL_STATUS_FLASH_VERIFY_FAILED ((sl_status_t)0x003C) ///< Flash verification failed.
#define SL_STATUS_FLASH_PROGRAM_FAILED ((sl_status_t)0x003D) ///< Flash programming failed.
#define SL_STATUS_FLASH_ERASE_FAILED ((sl_status_t)0x003E) ///< Flash erase failed.
// MAC Errors
#define SL_STATUS_MAC_NO_DATA ((sl_status_t)0x003F) ///< MAC no data.
#define SL_STATUS_MAC_NO_ACK_RECEIVED ((sl_status_t)0x0040) ///< MAC no ACK received.
#define SL_STATUS_MAC_INDIRECT_TIMEOUT ((sl_status_t)0x0041) ///< MAC indirect timeout.
#define SL_STATUS_MAC_UNKNOWN_HEADER_TYPE ((sl_status_t)0x0042) ///< MAC unknown header type.
#define SL_STATUS_MAC_ACK_HEADER_TYPE ((sl_status_t)0x0043) ///< MAC ACK unknown header type.
#define SL_STATUS_MAC_COMMAND_TRANSMIT_FAILURE ((sl_status_t)0x0044) ///< MAC command transmit failure.
// CLI_STORAGE Errors
#define SL_STATUS_CLI_STORAGE_NVM_OPEN_ERROR ((sl_status_t)0x0045) ///< Error in open NVM
// Security status codes
#define SL_STATUS_SECURITY_IMAGE_CHECKSUM_ERROR ((sl_status_t)0x0046) ///< Image checksum is not valid.
#define SL_STATUS_SECURITY_DECRYPT_ERROR ((sl_status_t)0x0047) ///< Decryption failed
// Command status codes
#define SL_STATUS_COMMAND_IS_INVALID ((sl_status_t)0x0048) ///< Command was not recognized
#define SL_STATUS_COMMAND_TOO_LONG ((sl_status_t)0x0049) ///< Command or parameter maximum length exceeded
#define SL_STATUS_COMMAND_INCOMPLETE ((sl_status_t)0x004A) ///< Data received does not form a complete command
// Misc Errors
#define SL_STATUS_BUS_ERROR ((sl_status_t)0x004B) ///< Bus error, e.g. invalid DMA address
// Unified MAC Errors
#define SL_STATUS_CCA_FAILURE ((sl_status_t)0x004C) ///< CCA failure.
// Scan errors
#define SL_STATUS_MAC_SCANNING ((sl_status_t)0x004D) ///< MAC scanning.
#define SL_STATUS_MAC_INCORRECT_SCAN_TYPE ((sl_status_t)0x004E) ///< MAC incorrect scan type.
#define SL_STATUS_INVALID_CHANNEL_MASK ((sl_status_t)0x004F) ///< Invalid channel mask.
#define SL_STATUS_BAD_SCAN_DURATION ((sl_status_t)0x0050) ///< Bad scan duration.
// MAC transmit related status
#define SL_STATUS_MAC_TRANSMIT_QUEUE_FULL ((sl_status_t)0x0053) ///< The MAC transmit queue is full
#define SL_STATUS_TRANSMIT_SCHEDULER_FAIL ((sl_status_t)0x0054) ///< The transmit attempt failed because the radio scheduler could not find a slot to transmit this packet in or a higher priority event interrupted it
#define SL_STATUS_TRANSMIT_INVALID_CHANNEL ((sl_status_t)0x0055) ///< An unsupported channel setting was specified
#define SL_STATUS_TRANSMIT_INVALID_POWER ((sl_status_t)0x0056) ///< An unsupported power setting was specified
#define SL_STATUS_TRANSMIT_ACK_RECEIVED ((sl_status_t)0x0057) ///< The expected ACK was received after the last transmission
#define SL_STATUS_TRANSMIT_BLOCKED ((sl_status_t)0x0058) ///< The transmit attempt was blocked from going over the air. Typically this is due to the Radio Hold Off (RHO) or Coexistence plugins as they can prevent transmits based on external signals.
// NVM3 specific errors
#define SL_STATUS_NVM3_ALIGNMENT_INVALID ((sl_status_t)0x0059) ///< The initialization was aborted as the NVM3 instance is not aligned properly in memory
#define SL_STATUS_NVM3_SIZE_TOO_SMALL ((sl_status_t)0x005A) ///< The initialization was aborted as the size of the NVM3 instance is too small
#define SL_STATUS_NVM3_PAGE_SIZE_NOT_SUPPORTED ((sl_status_t)0x005B) ///< The initialization was aborted as the NVM3 page size is not supported
#define SL_STATUS_NVM3_TOKEN_INIT_FAILED ((sl_status_t)0x005C) ///< The application that there was an error initializing some of the tokens
#define SL_STATUS_NVM3_OPENED_WITH_OTHER_PARAMETERS ((sl_status_t)0x005D) ///< The initialization was aborted as the NVM3 instance was already opened with other parameters
#define SL_STATUS_NVM3_NO_VALID_PAGES ((sl_status_t)0x005E) ///< Initialization aborted, no valid page found
#define SL_STATUS_NVM3_OBJECT_SIZE_NOT_SUPPORTED ((sl_status_t)0x005F) ///< The object size is not supported
#define SL_STATUS_NVM3_OBJECT_IS_NOT_DATA ((sl_status_t)0x0060) ///< Trying to access a data object which is currently a counter object
#define SL_STATUS_NVM3_OBJECT_IS_NOT_A_COUNTER ((sl_status_t)0x0061) ///< Trying to access a counter object which is currently a data object
#define SL_STATUS_NVM3_WRITE_DATA_SIZE ((sl_status_t)0x0062) ///< The object is too large
#define SL_STATUS_NVM3_READ_DATA_SIZE ((sl_status_t)0x0063) ///< Trying to read with a length different from actual object size
#define SL_STATUS_NVM3_INIT_WITH_FULL_NVM ((sl_status_t)0x0064) ///< The module was opened with a full NVM
#define SL_STATUS_NVM3_RESIZE_PARAMETER ((sl_status_t)0x0065) ///< Illegal parameter
#define SL_STATUS_NVM3_RESIZE_NOT_ENOUGH_SPACE ((sl_status_t)0x0066) ///< Not enough NVM to complete resize
#define SL_STATUS_NVM3_ERASE_COUNT_ERROR ((sl_status_t)0x0067) ///< Erase counts are not valid
#define SL_STATUS_NVM3_NVM_ACCESS ((sl_status_t)0x0068) ///< A NVM function call was failing
#define SL_STATUS_NVM3_CRYPTO_INIT_FAILED ((sl_status_t)0x0069) ///< Crypto initialization failed
#define SL_STATUS_NVM3_ENCRYPTION_KEY_ERROR ((sl_status_t)0x006A) ///< Error in obtaining encryption key
#define SL_STATUS_NVM3_RANDOM_NUM_GENERATION_FAILED ((sl_status_t)0x006B) ///< Error in obtaining random number
#define SL_STATUS_NVM3_ENCRYPTION_FAILED ((sl_status_t)0x006C) ///< Encryption failed
#define SL_STATUS_NVM3_WRITE_TO_NOT_ERASED ((sl_status_t)0x006D) ///< Write to memory that is not erased
#define SL_STATUS_NVM3_INVALID_ADDR ((sl_status_t)0x006E) ///< Invalid NVM address
#define SL_STATUS_NVM3_KEY_MISMATCH ((sl_status_t)0x006F) ///< Key validation failure
#define SL_STATUS_NVM3_SIZE_ERROR ((sl_status_t)0x0070) ///< Size mismatch error
#define SL_STATUS_NVM3_EMULATOR ((sl_status_t)0x0071) ///< Emulator error
#define SL_STATUS_NVM3_SECURITY_INIT_FAILED ((sl_status_t)0x0072) ///< Security init failed
#define SL_STATUS_NVM3_GET_REGION_LOCATION_FAILED ((sl_status_t)0x0073) ///< Get data region location failed
// Bluetooth status codes
#define SL_STATUS_BT_OUT_OF_BONDS ((sl_status_t)0x0402) ///< Bonding procedure can't be started because device has no space left for bond.
#define SL_STATUS_BT_UNSPECIFIED ((sl_status_t)0x0403) ///< Unspecified error
#define SL_STATUS_BT_HARDWARE ((sl_status_t)0x0404) ///< Hardware failure
#define SL_STATUS_BT_NO_BONDING ((sl_status_t)0x0406) ///< The bonding does not exist.
#define SL_STATUS_BT_CRYPTO ((sl_status_t)0x0407) ///< Error using crypto functions
#define SL_STATUS_BT_DATA_CORRUPTED ((sl_status_t)0x0408) ///< Data was corrupted.
#define SL_STATUS_BT_INVALID_SYNC_HANDLE ((sl_status_t)0x040A) ///< Invalid periodic advertising sync handle
#define SL_STATUS_BT_INVALID_MODULE_ACTION ((sl_status_t)0x040B) ///< Bluetooth cannot be used on this hardware
#define SL_STATUS_BT_RADIO ((sl_status_t)0x040C) ///< Error received from radio
#define SL_STATUS_BT_L2CAP_REMOTE_DISCONNECTED ((sl_status_t)0x040D) ///< Returned when remote disconnects the connection-oriented channel by sending disconnection request.
#define SL_STATUS_BT_L2CAP_LOCAL_DISCONNECTED ((sl_status_t)0x040E) ///< Returned when local host disconnect the connection-oriented channel by sending disconnection request.
#define SL_STATUS_BT_L2CAP_CID_NOT_EXIST ((sl_status_t)0x040F) ///< Returned when local host did not find a connection-oriented channel with given destination CID.
#define SL_STATUS_BT_L2CAP_LE_DISCONNECTED ((sl_status_t)0x0410) ///< Returned when connection-oriented channel disconnected due to LE connection is dropped.
#define SL_STATUS_BT_L2CAP_FLOW_CONTROL_VIOLATED ((sl_status_t)0x0412) ///< Returned when connection-oriented channel disconnected due to remote end send data even without credit.
#define SL_STATUS_BT_L2CAP_FLOW_CONTROL_CREDIT_OVERFLOWED ((sl_status_t)0x0413) ///< Returned when connection-oriented channel disconnected due to remote end send flow control credits exceed 65535.
#define SL_STATUS_BT_L2CAP_NO_FLOW_CONTROL_CREDIT ((sl_status_t)0x0414) ///< Returned when connection-oriented channel has run out of flow control credit and local application still trying to send data.
#define SL_STATUS_BT_L2CAP_CONNECTION_REQUEST_TIMEOUT ((sl_status_t)0x0415) ///< Returned when connection-oriented channel has not received connection response message within maximum timeout.
#define SL_STATUS_BT_L2CAP_INVALID_CID ((sl_status_t)0x0416) ///< Returned when local host received a connection-oriented channel connection response with an invalid destination CID.
#define SL_STATUS_BT_L2CAP_WRONG_STATE ((sl_status_t)0x0417) ///< Returned when local host application tries to send a command which is not suitable for L2CAP channel's current state.
#define SL_STATUS_BT_PS_STORE_FULL ((sl_status_t)0x041B) ///< Flash reserved for PS store is full
#define SL_STATUS_BT_PS_KEY_NOT_FOUND ((sl_status_t)0x041C) ///< PS key not found
#define SL_STATUS_BT_APPLICATION_MISMATCHED_OR_INSUFFICIENT_SECURITY ((sl_status_t)0x041D) ///< Mismatched or insufficient security level
#define SL_STATUS_BT_APPLICATION_ENCRYPTION_DECRYPTION_ERROR ((sl_status_t)0x041E) ///< Encryption/decryption operation failed.
// Bluetooth controller status codes
#define SL_STATUS_BT_CTRL_UNKNOWN_CONNECTION_IDENTIFIER ((sl_status_t)0x1002) ///< Connection does not exist, or connection open request was cancelled.
#define SL_STATUS_BT_CTRL_AUTHENTICATION_FAILURE ((sl_status_t)0x1005) ///< Pairing or authentication failed due to incorrect results in the pairing or authentication procedure. This could be due to an incorrect PIN or Link Key
#define SL_STATUS_BT_CTRL_PIN_OR_KEY_MISSING ((sl_status_t)0x1006) ///< Pairing failed because of missing PIN, or authentication failed because of missing Key
#define SL_STATUS_BT_CTRL_MEMORY_CAPACITY_EXCEEDED ((sl_status_t)0x1007) ///< Controller is out of memory.
#define SL_STATUS_BT_CTRL_CONNECTION_TIMEOUT ((sl_status_t)0x1008) ///< Link supervision timeout has expired.
#define SL_STATUS_BT_CTRL_CONNECTION_LIMIT_EXCEEDED ((sl_status_t)0x1009) ///< Controller is at limit of connections it can support.
#define SL_STATUS_BT_CTRL_SYNCHRONOUS_CONNECTION_LIMIT_EXCEEDED ((sl_status_t)0x100A) ///< The Synchronous Connection Limit to a Device Exceeded error code indicates that the Controller has reached the limit to the number of synchronous connections that can be achieved to a device.
#define SL_STATUS_BT_CTRL_ACL_CONNECTION_ALREADY_EXISTS ((sl_status_t)0x100B) ///< The ACL Connection Already Exists error code indicates that an attempt to create a new ACL Connection to a device when there is already a connection to this device.
#define SL_STATUS_BT_CTRL_COMMAND_DISALLOWED ((sl_status_t)0x100C) ///< Command requested cannot be executed because the Controller is in a state where it cannot process this command at this time.
#define SL_STATUS_BT_CTRL_CONNECTION_REJECTED_DUE_TO_LIMITED_RESOURCES ((sl_status_t)0x100D) ///< The Connection Rejected Due To Limited Resources error code indicates that an incoming connection was rejected due to limited resources.
#define SL_STATUS_BT_CTRL_CONNECTION_REJECTED_DUE_TO_SECURITY_REASONS ((sl_status_t)0x100E) ///< The Connection Rejected Due To Security Reasons error code indicates that a connection was rejected due to security requirements not being fulfilled, like authentication or pairing.
#define SL_STATUS_BT_CTRL_CONNECTION_REJECTED_DUE_TO_UNACCEPTABLE_BD_ADDR ((sl_status_t)0x100F) ///< The Connection was rejected because this device does not accept the BD_ADDR. This may be because the device will only accept connections from specific BD_ADDRs.
#define SL_STATUS_BT_CTRL_CONNECTION_ACCEPT_TIMEOUT_EXCEEDED ((sl_status_t)0x1010) ///< The Connection Accept Timeout has been exceeded for this connection attempt.
#define SL_STATUS_BT_CTRL_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE ((sl_status_t)0x1011) ///< A feature or parameter value in the HCI command is not supported.
#define SL_STATUS_BT_CTRL_INVALID_COMMAND_PARAMETERS ((sl_status_t)0x1012) ///< Command contained invalid parameters.
#define SL_STATUS_BT_CTRL_REMOTE_USER_TERMINATED ((sl_status_t)0x1013) ///< User on the remote device terminated the connection.
#define SL_STATUS_BT_CTRL_REMOTE_DEVICE_TERMINATED_CONNECTION_DUE_TO_LOW_RESOURCES ((sl_status_t)0x1014) ///< The remote device terminated the connection because of low resources
#define SL_STATUS_BT_CTRL_REMOTE_POWERING_OFF ((sl_status_t)0x1015) ///< Remote Device Terminated Connection due to Power Off
#define SL_STATUS_BT_CTRL_CONNECTION_TERMINATED_BY_LOCAL_HOST ((sl_status_t)0x1016) ///< Local device terminated the connection.
#define SL_STATUS_BT_CTRL_REPEATED_ATTEMPTS ((sl_status_t)0x1017) ///< The Controller is disallowing an authentication or pairing procedure because too little time has elapsed since the last authentication or pairing attempt failed.
#define SL_STATUS_BT_CTRL_PAIRING_NOT_ALLOWED ((sl_status_t)0x1018) ///< The device does not allow pairing. This can be for example, when a device only allows pairing during a certain time window after some user input allows pairing
#define SL_STATUS_BT_CTRL_UNSUPPORTED_REMOTE_FEATURE ((sl_status_t)0x101A) ///< The remote device does not support the feature associated with the issued command.
#define SL_STATUS_BT_CTRL_INVALID_LL_PARAMETERS ((sl_status_t)0x101E) ///< Indicates that some LMP PDU / LL Control PDU parameters were invalid
#define SL_STATUS_BT_CTRL_UNSPECIFIED_ERROR ((sl_status_t)0x101F) ///< No other error code specified is appropriate to use.
#define SL_STATUS_BT_CTRL_LL_RESPONSE_TIMEOUT ((sl_status_t)0x1022) ///< Connection terminated due to link-layer procedure timeout.
#define SL_STATUS_BT_CTRL_LL_PROCEDURE_COLLISION ((sl_status_t)0x1023) ///< LL procedure has collided with the same transaction or procedure that is already in progress.
#define SL_STATUS_BT_CTRL_ENCRYPTION_MODE_NOT_ACCEPTABLE ((sl_status_t)0x1025) ///< The requested encryption mode is not acceptable at this time.
#define SL_STATUS_BT_CTRL_LINK_KEY_CANNOT_BE_CHANGED ((sl_status_t)0x1026) ///< Link key cannot be changed because a fixed unit key is being used.
#define SL_STATUS_BT_CTRL_INSTANT_PASSED ((sl_status_t)0x1028) ///< LMP PDU or LL PDU that includes an instant cannot be performed because the instant when this would have occurred has passed.
#define SL_STATUS_BT_CTRL_PAIRING_WITH_UNIT_KEY_NOT_SUPPORTED ((sl_status_t)0x1029) ///< It was not possible to pair as a unit key was requested and it is not supported.
#define SL_STATUS_BT_CTRL_DIFFERENT_TRANSACTION_COLLISION ((sl_status_t)0x102A) ///< LMP transaction was started that collides with an ongoing transaction.
#define SL_STATUS_BT_CTRL_CHANNEL_ASSESSMENT_NOT_SUPPORTED ((sl_status_t)0x102E) ///< The Controller cannot perform channel assessment because it is not supported.
#define SL_STATUS_BT_CTRL_INSUFFICIENT_SECURITY ((sl_status_t)0x102F) ///< The HCI command or LMP PDU sent is only possible on an encrypted link.
#define SL_STATUS_BT_CTRL_PARAMETER_OUT_OF_MANDATORY_RANGE ((sl_status_t)0x1030) ///< A parameter value requested is outside the mandatory range of parameters for the given HCI command or LMP PDU.
#define SL_STATUS_BT_CTRL_SIMPLE_PAIRING_NOT_SUPPORTED_BY_HOST ((sl_status_t)0x1037) ///< The IO capabilities request or response was rejected because the sending Host does not support Secure Simple Pairing even though the receiving Link Manager does.
#define SL_STATUS_BT_CTRL_HOST_BUSY_PAIRING ((sl_status_t)0x1038) ///< The Host is busy with another pairing operation and unable to support the requested pairing. The receiving device should retry pairing again later.
#define SL_STATUS_BT_CTRL_CONNECTION_REJECTED_DUE_TO_NO_SUITABLE_CHANNEL_FOUND ((sl_status_t)0x1039) ///< The Controller could not calculate an appropriate value for the Channel selection operation.
#define SL_STATUS_BT_CTRL_CONTROLLER_BUSY ((sl_status_t)0x103A) ///< Operation was rejected because the controller is busy and unable to process the request.
#define SL_STATUS_BT_CTRL_UNACCEPTABLE_CONNECTION_INTERVAL ((sl_status_t)0x103B) ///< Remote device terminated the connection because of an unacceptable connection interval.
#define SL_STATUS_BT_CTRL_ADVERTISING_TIMEOUT ((sl_status_t)0x103C) ///< Advertising for a fixed duration completed or, for directed advertising, that advertising completed without a connection being created.
#define SL_STATUS_BT_CTRL_CONNECTION_TERMINATED_DUE_TO_MIC_FAILURE ((sl_status_t)0x103D) ///< Connection was terminated because the Message Integrity Check (MIC) failed on a received packet.
#define SL_STATUS_BT_CTRL_CONNECTION_FAILED_TO_BE_ESTABLISHED ((sl_status_t)0x103E) ///< LL initiated a connection but the connection has failed to be established. Controller did not receive any packets from remote end.
#define SL_STATUS_BT_CTRL_MAC_CONNECTION_FAILED ((sl_status_t)0x103F) ///< The MAC of the 802.11 AMP was requested to connect to a peer, but the connection failed.
#define SL_STATUS_BT_CTRL_COARSE_CLOCK_ADJUSTMENT_REJECTED_BUT_WILL_TRY_TO_ADJUST_USING_CLOCK_DRAGGING ((sl_status_t)0x1040) ///< The master, at this time, is unable to make a coarse adjustment to the piconet clock, using the supplied parameters. Instead the master will attempt to move the clock using clock dragging.
#define SL_STATUS_BT_CTRL_UNKNOWN_ADVERTISING_IDENTIFIER ((sl_status_t)0x1042) ///< A command was sent from the Host that should identify an Advertising or Sync handle, but the Advertising or Sync handle does not exist.
#define SL_STATUS_BT_CTRL_LIMIT_REACHED ((sl_status_t)0x1043) ///< Number of operations requested has been reached and has indicated the completion of the activity (e.g., advertising or scanning).
#define SL_STATUS_BT_CTRL_OPERATION_CANCELLED_BY_HOST ((sl_status_t)0x1044) ///< A request to the Controller issued by the Host and still pending was successfully canceled.
#define SL_STATUS_BT_CTRL_PACKET_TOO_LONG ((sl_status_t)0x1045) ///< An attempt was made to send or receive a packet that exceeds the maximum allowed packet length.
#define SL_STATUS_BT_CTRL_TOO_LATE ((sl_status_t)0x1046) ///< Information was provided too late to the controller.
#define SL_STATUS_BT_CTRL_TOO_EARLY ((sl_status_t)0x1047) ///< Information was provided too early to the controller.
#define SL_STATUS_BT_CTRL_INSUFFICIENT_CHANNELS ((sl_status_t)0x1048) ///< Indicates that the result of the requested operation would yield too few physical channels.
// Bluetooth attribute status codes
#define SL_STATUS_BT_ATT_INVALID_HANDLE ((sl_status_t)0x1101) ///< The attribute handle given was not valid on this server
#define SL_STATUS_BT_ATT_READ_NOT_PERMITTED ((sl_status_t)0x1102) ///< The attribute cannot be read
#define SL_STATUS_BT_ATT_WRITE_NOT_PERMITTED ((sl_status_t)0x1103) ///< The attribute cannot be written
#define SL_STATUS_BT_ATT_INVALID_PDU ((sl_status_t)0x1104) ///< The attribute PDU was invalid
#define SL_STATUS_BT_ATT_INSUFFICIENT_AUTHENTICATION ((sl_status_t)0x1105) ///< The attribute requires authentication before it can be read or written.
#define SL_STATUS_BT_ATT_REQUEST_NOT_SUPPORTED ((sl_status_t)0x1106) ///< Attribute Server does not support the request received from the client.
#define SL_STATUS_BT_ATT_INVALID_OFFSET ((sl_status_t)0x1107) ///< Offset specified was past the end of the attribute
#define SL_STATUS_BT_ATT_INSUFFICIENT_AUTHORIZATION ((sl_status_t)0x1108) ///< The attribute requires authorization before it can be read or written.
#define SL_STATUS_BT_ATT_PREPARE_QUEUE_FULL ((sl_status_t)0x1109) ///< Too many prepare writes have been queued
#define SL_STATUS_BT_ATT_ATT_NOT_FOUND ((sl_status_t)0x110A) ///< No attribute found within the given attribute handle range.
#define SL_STATUS_BT_ATT_ATT_NOT_LONG ((sl_status_t)0x110B) ///< The attribute cannot be read or written using the Read Blob Request
#define SL_STATUS_BT_ATT_INSUFFICIENT_ENC_KEY_SIZE ((sl_status_t)0x110C) ///< The Encryption Key Size used for encrypting this link is insufficient.
#define SL_STATUS_BT_ATT_INVALID_ATT_LENGTH ((sl_status_t)0x110D) ///< The attribute value length is invalid for the operation
#define SL_STATUS_BT_ATT_UNLIKELY_ERROR ((sl_status_t)0x110E) ///< The attribute request that was requested has encountered an error that was unlikely, and therefore could not be completed as requested.
#define SL_STATUS_BT_ATT_INSUFFICIENT_ENCRYPTION ((sl_status_t)0x110F) ///< The attribute requires encryption before it can be read or written.
#define SL_STATUS_BT_ATT_UNSUPPORTED_GROUP_TYPE ((sl_status_t)0x1110) ///< The attribute type is not a supported grouping attribute as defined by a higher layer specification.
#define SL_STATUS_BT_ATT_INSUFFICIENT_RESOURCES ((sl_status_t)0x1111) ///< Insufficient Resources to complete the request
#define SL_STATUS_BT_ATT_OUT_OF_SYNC ((sl_status_t)0x1112) ///< The server requests the client to rediscover the database.
#define SL_STATUS_BT_ATT_VALUE_NOT_ALLOWED ((sl_status_t)0x1113) ///< The attribute parameter value was not allowed.
#define SL_STATUS_BT_ATT_APPLICATION ((sl_status_t)0x1180) ///< When this is returned in a BGAPI response, the application tried to read or write the value of a user attribute from the GATT database.
#define SL_STATUS_BT_ATT_WRITE_REQUEST_REJECTED ((sl_status_t)0x11FC) ///< The requested write operation cannot be fulfilled for reasons other than permissions.
#define SL_STATUS_BT_ATT_CLIENT_CHARACTERISTIC_CONFIGURATION_DESCRIPTOR_IMPROPERLY_CONFIGURED ((sl_status_t)0x11FD) ///< The Client Characteristic Configuration descriptor is not configured according to the requirements of the profile or service.
#define SL_STATUS_BT_ATT_PROCEDURE_ALREADY_IN_PROGRESS ((sl_status_t)0x11FE) ///< The profile or service request cannot be serviced because an operation that has been previously triggered is still in progress.
#define SL_STATUS_BT_ATT_OUT_OF_RANGE ((sl_status_t)0x11FF) ///< The attribute value is out of range as defined by a profile or service specification.
// Bluetooth Security Manager Protocol status codes
#define SL_STATUS_BT_SMP_PASSKEY_ENTRY_FAILED ((sl_status_t)0x1201) ///< The user input of passkey failed, for example, the user cancelled the operation
#define SL_STATUS_BT_SMP_OOB_NOT_AVAILABLE ((sl_status_t)0x1202) ///< Out of Band data is not available for authentication
#define SL_STATUS_BT_SMP_AUTHENTICATION_REQUIREMENTS ((sl_status_t)0x1203) ///< The pairing procedure cannot be performed as authentication requirements cannot be met due to IO capabilities of one or both devices
#define SL_STATUS_BT_SMP_CONFIRM_VALUE_FAILED ((sl_status_t)0x1204) ///< The confirm value does not match the calculated compare value
#define SL_STATUS_BT_SMP_PAIRING_NOT_SUPPORTED ((sl_status_t)0x1205) ///< Pairing is not supported by the device
#define SL_STATUS_BT_SMP_ENCRYPTION_KEY_SIZE ((sl_status_t)0x1206) ///< The resultant encryption key size is insufficient for the security requirements of this device
#define SL_STATUS_BT_SMP_COMMAND_NOT_SUPPORTED ((sl_status_t)0x1207) ///< The SMP command received is not supported on this device
#define SL_STATUS_BT_SMP_UNSPECIFIED_REASON ((sl_status_t)0x1208) ///< Pairing failed due to an unspecified reason
#define SL_STATUS_BT_SMP_REPEATED_ATTEMPTS ((sl_status_t)0x1209) ///< Pairing or authentication procedure is disallowed because too little time has elapsed since last pairing request or security request
#define SL_STATUS_BT_SMP_INVALID_PARAMETERS ((sl_status_t)0x120A) ///< The Invalid Parameters error code indicates: the command length is invalid or a parameter is outside of the specified range.
#define SL_STATUS_BT_SMP_DHKEY_CHECK_FAILED ((sl_status_t)0x120B) ///< Indicates to the remote device that the DHKey Check value received doesn't match the one calculated by the local device.
#define SL_STATUS_BT_SMP_NUMERIC_COMPARISON_FAILED ((sl_status_t)0x120C) ///< Indicates that the confirm values in the numeric comparison protocol do not match.
#define SL_STATUS_BT_SMP_BREDR_PAIRING_IN_PROGRESS ((sl_status_t)0x120D) ///< Indicates that the pairing over the LE transport failed due to a Pairing Request sent over the BR/EDR transport in process.
#define SL_STATUS_BT_SMP_CROSS_TRANSPORT_KEY_DERIVATION_GENERATION_NOT_ALLOWED ((sl_status_t)0x120E) ///< Indicates that the BR/EDR Link Key generated on the BR/EDR transport cannot be used to derive and distribute keys for the LE transport.
#define SL_STATUS_BT_SMP_KEY_REJECTED ((sl_status_t)0x120F) ///< Indicates that the device chose not to accept a distributed key.
// Bluetooth Mesh status codes
#define SL_STATUS_BT_MESH_ALREADY_EXISTS ((sl_status_t)0x0501) ///< Returned when trying to add a key or some other unique resource with an ID which already exists
#define SL_STATUS_BT_MESH_DOES_NOT_EXIST ((sl_status_t)0x0502) ///< Returned when trying to manipulate a key or some other resource with an ID which does not exist
#define SL_STATUS_BT_MESH_LIMIT_REACHED ((sl_status_t)0x0503) ///< Returned when an operation cannot be executed because a pre-configured limit for keys, key bindings, elements, models, virtual addresses, provisioned devices, or provisioning sessions is reached
#define SL_STATUS_BT_MESH_INVALID_ADDRESS ((sl_status_t)0x0504) ///< Returned when trying to use a reserved address or add a "pre-provisioned" device using an address already used by some other device
#define SL_STATUS_BT_MESH_MALFORMED_DATA ((sl_status_t)0x0505) ///< In a BGAPI response, the user supplied malformed data; in a BGAPI event, the remote end responded with malformed or unrecognized data
#define SL_STATUS_BT_MESH_ALREADY_INITIALIZED ((sl_status_t)0x0506) ///< An attempt was made to initialize a subsystem that was already initialized.
#define SL_STATUS_BT_MESH_NOT_INITIALIZED ((sl_status_t)0x0507) ///< An attempt was made to use a subsystem that wasn't initialized yet. Call the subsystem's init function first.
#define SL_STATUS_BT_MESH_NO_FRIEND_OFFER ((sl_status_t)0x0508) ///< Returned when trying to establish a friendship as a Low Power Node, but no acceptable friend offer message was received.
#define SL_STATUS_BT_MESH_PROV_LINK_CLOSED ((sl_status_t)0x0509) ///< Provisioning link was unexpectedly closed before provisioning was complete.
#define SL_STATUS_BT_MESH_PROV_INVALID_PDU ((sl_status_t)0x050A) ///< An unrecognized provisioning PDU was received.
#define SL_STATUS_BT_MESH_PROV_INVALID_PDU_FORMAT ((sl_status_t)0x050B) ///< A provisioning PDU with wrong length or containing field values that are out of bounds was received.
#define SL_STATUS_BT_MESH_PROV_UNEXPECTED_PDU ((sl_status_t)0x050C) ///< An unexpected (out of sequence) provisioning PDU was received.
#define SL_STATUS_BT_MESH_PROV_CONFIRMATION_FAILED ((sl_status_t)0x050D) ///< The computed confirmation value did not match the expected value.
#define SL_STATUS_BT_MESH_PROV_OUT_OF_RESOURCES ((sl_status_t)0x050E) ///< Provisioning could not be continued due to insufficient resources.
#define SL_STATUS_BT_MESH_PROV_DECRYPTION_FAILED ((sl_status_t)0x050F) ///< The provisioning data block could not be decrypted.
#define SL_STATUS_BT_MESH_PROV_UNEXPECTED_ERROR ((sl_status_t)0x0510) ///< An unexpected error happened during provisioning.
#define SL_STATUS_BT_MESH_PROV_CANNOT_ASSIGN_ADDR ((sl_status_t)0x0511) ///< Device could not assign unicast addresses to all of its elements.
#define SL_STATUS_BT_MESH_ADDRESS_TEMPORARILY_UNAVAILABLE ((sl_status_t)0x0512) ///< Returned when trying to reuse an address of a previously deleted device before an IV Index Update has been executed.
#define SL_STATUS_BT_MESH_ADDRESS_ALREADY_USED ((sl_status_t)0x0513) ///< Returned when trying to assign an address that is used by one of the devices in the Device Database, or by the Provisioner itself.
#define SL_STATUS_BT_MESH_PUBLISH_NOT_CONFIGURED ((sl_status_t)0x0514) ///< Application key or publish address are not set
#define SL_STATUS_BT_MESH_APP_KEY_NOT_BOUND ((sl_status_t)0x0515) ///< Application key is not bound to a model
// Bluetooth Mesh foundation status codes
#define SL_STATUS_BT_MESH_FOUNDATION_INVALID_ADDRESS ((sl_status_t)0x1301) ///< Returned when address in request was not valid
#define SL_STATUS_BT_MESH_FOUNDATION_INVALID_MODEL ((sl_status_t)0x1302) ///< Returned when model identified is not found for a given element
#define SL_STATUS_BT_MESH_FOUNDATION_INVALID_APP_KEY ((sl_status_t)0x1303) ///< Returned when the key identified by AppKeyIndex is not stored in the node
#define SL_STATUS_BT_MESH_FOUNDATION_INVALID_NET_KEY ((sl_status_t)0x1304) ///< Returned when the key identified by NetKeyIndex is not stored in the node
#define SL_STATUS_BT_MESH_FOUNDATION_INSUFFICIENT_RESOURCES ((sl_status_t)0x1305) ///< Returned when The node cannot serve the request due to insufficient resources
#define SL_STATUS_BT_MESH_FOUNDATION_KEY_INDEX_EXISTS ((sl_status_t)0x1306) ///< Returned when the key identified is already stored in the node and the new NetKey value is different
#define SL_STATUS_BT_MESH_FOUNDATION_INVALID_PUBLISH_PARAMS ((sl_status_t)0x1307) ///< Returned when the model does not support the publish mechanism
#define SL_STATUS_BT_MESH_FOUNDATION_NOT_SUBSCRIBE_MODEL ((sl_status_t)0x1308) ///< Returned when the model does not support the subscribe mechanism
#define SL_STATUS_BT_MESH_FOUNDATION_STORAGE_FAILURE ((sl_status_t)0x1309) ///< Returned when storing of the requested parameters failed
#define SL_STATUS_BT_MESH_FOUNDATION_NOT_SUPPORTED ((sl_status_t)0x130A) ///< Returned when requested setting is not supported
#define SL_STATUS_BT_MESH_FOUNDATION_CANNOT_UPDATE ((sl_status_t)0x130B) ///< Returned when the requested update operation cannot be performed due to general constraints
#define SL_STATUS_BT_MESH_FOUNDATION_CANNOT_REMOVE ((sl_status_t)0x130C) ///< Returned when the requested delete operation cannot be performed due to general constraints
#define SL_STATUS_BT_MESH_FOUNDATION_CANNOT_BIND ((sl_status_t)0x130D) ///< Returned when the requested bind operation cannot be performed due to general constraints
#define SL_STATUS_BT_MESH_FOUNDATION_TEMPORARILY_UNABLE ((sl_status_t)0x130E) ///< Returned when The node cannot start advertising with Node Identity or Proxy since the maximum number of parallel advertising is reached
#define SL_STATUS_BT_MESH_FOUNDATION_CANNOT_SET ((sl_status_t)0x130F) ///< Returned when the requested state cannot be set
#define SL_STATUS_BT_MESH_FOUNDATION_UNSPECIFIED ((sl_status_t)0x1310) ///< Returned when an unspecified error took place
#define SL_STATUS_BT_MESH_FOUNDATION_INVALID_BINDING ((sl_status_t)0x1311) ///< Returned when the NetKeyIndex and AppKeyIndex combination is not valid for a Config AppKey Update
// -----------------------------------------------------------------------------
// Wi-Fi Errors
#define SL_STATUS_WIFI_INVALID_KEY ((sl_status_t)0x0B01) ///< Invalid firmware keyset
#define SL_STATUS_WIFI_FIRMWARE_DOWNLOAD_TIMEOUT ((sl_status_t)0x0B02) ///< The firmware download took too long
#define SL_STATUS_WIFI_UNSUPPORTED_MESSAGE_ID ((sl_status_t)0x0B03) ///< Unknown request ID or wrong interface ID used
#define SL_STATUS_WIFI_WARNING ((sl_status_t)0x0B04) ///< The request is successful but some parameters have been ignored
#define SL_STATUS_WIFI_NO_PACKET_TO_RECEIVE ((sl_status_t)0x0B05) ///< No Packets waiting to be received
#define SL_STATUS_WIFI_SLEEP_GRANTED ((sl_status_t)0x0B08) ///< The sleep mode is granted
#define SL_STATUS_WIFI_SLEEP_NOT_GRANTED ((sl_status_t)0x0B09) ///< The WFx does not go back to sleep
#define SL_STATUS_WIFI_SECURE_LINK_MAC_KEY_ERROR ((sl_status_t)0x0B10) ///< The SecureLink MAC key was not found
#define SL_STATUS_WIFI_SECURE_LINK_MAC_KEY_ALREADY_BURNED ((sl_status_t)0x0B11) ///< The SecureLink MAC key is already installed in OTP
#define SL_STATUS_WIFI_SECURE_LINK_RAM_MODE_NOT_ALLOWED ((sl_status_t)0x0B12) ///< The SecureLink MAC key cannot be installed in RAM
#define SL_STATUS_WIFI_SECURE_LINK_FAILED_UNKNOWN_MODE ((sl_status_t)0x0B13) ///< The SecureLink MAC key installation failed
#define SL_STATUS_WIFI_SECURE_LINK_EXCHANGE_FAILED ((sl_status_t)0x0B14) ///< SecureLink key (re)negotiation failed
#define SL_STATUS_WIFI_WRONG_STATE ((sl_status_t)0x0B18) ///< The device is in an inappropriate state to perform the request
#define SL_STATUS_WIFI_CHANNEL_NOT_ALLOWED ((sl_status_t)0x0B19) ///< The request failed due to regulatory limitations
#define SL_STATUS_WIFI_NO_MATCHING_AP ((sl_status_t)0x0B1A) ///< The connection request failed because no suitable AP was found
#define SL_STATUS_WIFI_CONNECTION_ABORTED ((sl_status_t)0x0B1B) ///< The connection request was aborted by host
#define SL_STATUS_WIFI_CONNECTION_TIMEOUT ((sl_status_t)0x0B1C) ///< The connection request failed because of a timeout
#define SL_STATUS_WIFI_CONNECTION_REJECTED_BY_AP ((sl_status_t)0x0B1D) ///< The connection request failed because the AP rejected the device
#define SL_STATUS_WIFI_CONNECTION_AUTH_FAILURE ((sl_status_t)0x0B1E) ///< The connection request failed because the WPA handshake did not complete successfully
#define SL_STATUS_WIFI_RETRY_EXCEEDED ((sl_status_t)0x0B1F) ///< The request failed because the retry limit was exceeded
#define SL_STATUS_WIFI_TX_LIFETIME_EXCEEDED ((sl_status_t)0x0B20) ///< The request failed because the MSDU life time was exceeded
// -----------------------------------------------------------------------------
// MVP Driver and MVP Math status codes
#define SL_STATUS_COMPUTE_DRIVER_FAULT ((sl_status_t)0x1501) ///< Critical fault
#define SL_STATUS_COMPUTE_DRIVER_ALU_NAN ((sl_status_t)0x1502) ///< ALU operation output NaN
#define SL_STATUS_COMPUTE_DRIVER_ALU_OVERFLOW ((sl_status_t)0x1503) ///< ALU numeric overflow
#define SL_STATUS_COMPUTE_DRIVER_ALU_UNDERFLOW ((sl_status_t)0x1504) ///< ALU numeric underflow
#define SL_STATUS_COMPUTE_DRIVER_STORE_CONVERSION_OVERFLOW ((sl_status_t)0x1505) ///< Overflow during array store
#define SL_STATUS_COMPUTE_DRIVER_STORE_CONVERSION_UNDERFLOW ((sl_status_t)0x1506) ///< Underflow during array store conversion
#define SL_STATUS_COMPUTE_DRIVER_STORE_CONVERSION_INFINITY ((sl_status_t)0x1507) ///< Infinity encountered during array store conversion
#define SL_STATUS_COMPUTE_DRIVER_STORE_CONVERSION_NAN ((sl_status_t)0x1508) ///< NaN encountered during array store conversion
#define SL_STATUS_COMPUTE_MATH_NAN ((sl_status_t)0x1512) ///< MATH NaN encountered
#define SL_STATUS_COMPUTE_MATH_INFINITY ((sl_status_t)0x1513) ///< MATH Infinity encountered
#define SL_STATUS_COMPUTE_MATH_OVERFLOW ((sl_status_t)0x1514) ///< MATH numeric overflow
#define SL_STATUS_COMPUTE_MATH_UNDERFLOW ((sl_status_t)0x1515) ///< MATH numeric underflow
// Zigbee status codes
#define SL_STATUS_ZIGBEE_PACKET_HANDOFF_DROPPED ((sl_status_t)0x0C01) ///< Packet is dropped by packet-handoff callbacks
#define SL_STATUS_ZIGBEE_DELIVERY_FAILED ((sl_status_t)0x0C02) ///< The APS layer attempted to send or deliver a message and failed
#define SL_STATUS_ZIGBEE_MAX_MESSAGE_LIMIT_REACHED ((sl_status_t)0x0C03) ///< The maximum number of in-flight messages ::EMBER_APS_UNICAST_MESSAGE_COUNT has been reached
#define SL_STATUS_ZIGBEE_BINDING_IS_ACTIVE ((sl_status_t)0x0C04) ///< The application is trying to delete or overwrite a binding that is in use
#define SL_STATUS_ZIGBEE_ADDRESS_TABLE_ENTRY_IS_ACTIVE ((sl_status_t)0x0C05) ///< The application is trying to overwrite an address table entry that is in use
#define SL_STATUS_ZIGBEE_MOVE_FAILED ((sl_status_t)0x0C06) ///< After moving, a mobile node's attempt to re-establish contact with the network failed
#define SL_STATUS_ZIGBEE_NODE_ID_CHANGED ((sl_status_t)0x0C07) ///< The local node ID has changed. The application can get the new node ID by calling ::sl_zigbee_get_node_id()
#define SL_STATUS_ZIGBEE_INVALID_SECURITY_LEVEL ((sl_status_t)0x0C08) ///< The chosen security level is not supported by the stack
#define SL_STATUS_ZIGBEE_IEEE_ADDRESS_DISCOVERY_IN_PROGRESS ((sl_status_t)0x0C09) ///< An error occurred when trying to encrypt at the APS Level
#define SL_STATUS_ZIGBEE_APS_ENCRYPTION_ERROR ((sl_status_t)0x0C0A) ///< An error occurred when trying to encrypt at the APS Level
#define SL_STATUS_ZIGBEE_SECURITY_STATE_NOT_SET ((sl_status_t)0x0C0B) ///< There was an attempt to form or join a network with security without calling ::sl_zigbee_set_initial_security_state() first
#define SL_STATUS_ZIGBEE_TOO_SOON_FOR_SWITCH_KEY ((sl_status_t)0x0C0C) ///< There was an attempt to broadcast a key switch too quickly after broadcasting the next network key. The Trust Center must wait at least a period equal to the broadcast timeout so that all routers have a chance to receive the broadcast of the new network key
#define SL_STATUS_ZIGBEE_SIGNATURE_VERIFY_FAILURE ((sl_status_t)0x0C0D) ///< The received signature corresponding to the message that was passed to the CBKE Library failed verification and is not valid
#define SL_STATUS_ZIGBEE_KEY_NOT_AUTHORIZED ((sl_status_t)0x0C0E) ///< The message could not be sent because the link key corresponding to the destination is not authorized for use in APS data messages
#define SL_STATUS_ZIGBEE_BINDING_HAS_CHANGED ((sl_status_t)0x0C0F) ///< The application tried to use a binding that has been remotely modified and the change has not yet been reported to the application
#define SL_STATUS_ZIGBEE_TRUST_CENTER_SWAP_EUI_HAS_CHANGED ((sl_status_t)0x0C10) ///< The EUI of the Trust center has changed due to a successful rejoin after TC Swapout
#define SL_STATUS_ZIGBEE_TRUST_CENTER_SWAP_EUI_HAS_NOT_CHANGED ((sl_status_t)0x0C11) ///< A Trust Center Swapout Rejoin has occurred without the EUI of the TC changing
#define SL_STATUS_ZIGBEE_INSUFFICIENT_RANDOM_DATA ((sl_status_t)0x0C12) ///< An attempt to generate random bytes failed because of insufficient random data from the radio
#define SL_STATUS_ZIGBEE_SOURCE_ROUTE_FAILURE ((sl_status_t)0x0C13) ///< A Zigbee route error command frame was received indicating that a source routed message from this node failed en route
#define SL_STATUS_ZIGBEE_MANY_TO_ONE_ROUTE_FAILURE ((sl_status_t)0x0C14) ///< A Zigbee route error command frame was received indicating that a message sent to this node along a many-to-one route failed en route
#define SL_STATUS_ZIGBEE_STACK_AND_HARDWARE_MISMATCH ((sl_status_t)0x0C15) ///< A critical and fatal error indicating that the version of the stack trying to run does not match with the chip it's running on
#define SL_STATUS_ZIGBEE_PAN_ID_CHANGED ((sl_status_t)0x0C16) ///< The local PAN ID has changed. The application can get the new PAN ID by calling ::emberGetPanId()
#define SL_STATUS_ZIGBEE_CHANNEL_CHANGED ((sl_status_t)0x0C17) ///< The channel has changed.
#define SL_STATUS_ZIGBEE_NETWORK_OPENED ((sl_status_t)0x0C18) ///< The network has been opened for joining.
#define SL_STATUS_ZIGBEE_NETWORK_CLOSED ((sl_status_t)0x0C19) ///< The network has been closed for joining.
#define SL_STATUS_ZIGBEE_RECEIVED_KEY_IN_THE_CLEAR ((sl_status_t)0x0C1A) ///< An attempt was made to join a Secured Network using a pre-configured key, but the Trust Center sent back a Network Key in-the-clear when an encrypted Network Key was required. (::EMBER_REQUIRE_ENCRYPTED_KEY)
#define SL_STATUS_ZIGBEE_NO_NETWORK_KEY_RECEIVED ((sl_status_t)0x0C1B) ///< An attempt was made to join a Secured Network, but the device did not receive a Network Key.
#define SL_STATUS_ZIGBEE_NO_LINK_KEY_RECEIVED ((sl_status_t)0x0C1C) ///< After a device joined a Secured Network, a Link Key was requested (::EMBER_GET_LINK_KEY_WHEN_JOINING) but no response was ever received.
#define SL_STATUS_ZIGBEE_PRECONFIGURED_KEY_REQUIRED ((sl_status_t)0x0C1D) ///< An attempt was made to join a Secured Network without a pre-configured key, but the Trust Center sent encrypted data using a pre-configured key.
#define SL_STATUS_ZIGBEE_EZSP_ERROR ((sl_status_t)0x0C1E) ///< A Zigbee EZSP error has occured. Track the origin and corresponding EzspStatus for more info.
// -----------------------------------------------------------------------------
// Data Types
/** @brief define global status variable. */
typedef uint32_t sl_status_t;
// -----------------------------------------------------------------------------
// Functions
#ifdef __cplusplus
extern "C" {
#endif
/********************************************************************************************************
* sl_status_get_string_n()
*
* @brief Get a copy of the status string associated to the status code passed, up to
* 'buffer_length' length, if the string associated to the status code is enabled. If not,
* the error code number, in hex, prefixed by "SL_STATUS_" will be copied in the buffer
* instead.
* For example, the buffer would either contain "SL_STATUS_FAIL" if that status string is
* enabled, or "SL_STATUS_0x0001" if the string is disabled, as SL_STATUS_FAIL's
* value is 0x0001.
*
* @param status The status code from which to obtain the status string.
*
* @param buffer Pointer to a buffer in which the status string will be copied. A terminating
* null-character will be appended after the copied status string.
*
* @param buffer_length Maximum number of characters that can be written in the buffer, including the
* terminating null-character. If the status string would be longer than the
* available length, it will be truncated and a null-terminating character will
* be the last character contained in the buffer.
*
* @return The number of characters that would have been written if the buffer_length had been
* sufficiently large, not counting the terminating null character.
* If the status code is invalid, 0 or a negative number is returned.
* Notice that only when this returned value is strictly positive and less than
* buffer_length, the status string has been completely written in the buffer.
*******************************************************************************************************/
int32_t sl_status_get_string_n(sl_status_t status, char *buffer, uint32_t buffer_length);
/********************************************************************************************************
* sl_status_print()
*
* @brief Print, through printf, the string associated to the passed status code. If the string
* associated to the status code is enabled, the status string will be printed, for example
* "SL_STATUS_OK". If the string associated to the status code is disabled, the status number,
* in hex, prefixed by "SL_STATUS_" will be printed instead, for example "SL_STATUS_0x0000",
* as SL_STATUS_OK's value is 0x0000.
*
* @param status The status code of which to print the status string.
*******************************************************************************************************/
void sl_status_print(sl_status_t status);
#ifdef __cplusplus
}
#endif
/** @} (end addtogroup status) */
#endif /* SL_STATUS_H */

View File

@@ -0,0 +1,108 @@
/***************************************************************************//**
* @file sli_cmsis_os2_ext_task_register.h
* @brief Abstraction for Task Registers (Thread Local Variables)
*******************************************************************************
* # License
* <b>Copyright 2020 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* 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.
*
******************************************************************************/
#ifndef SLI_CMSIS_OS2_EXT_TASK_REGISTER_H
#define SLI_CMSIS_OS2_EXT_TASK_REGISTER_H
#if defined(SL_COMPONENT_CATALOG_PRESENT)
#include "sl_component_catalog.h"
#endif
// Validate the chosen RTOS
#if !defined(SL_CATALOG_FREERTOS_KERNEL_PRESENT) && !defined(SL_CATALOG_MICRIUMOS_KERNEL_PRESENT)
#error "The task register API currently only supports FreeRTOS or MicriumOS"
#endif
#if defined(SL_CATALOG_FREERTOS_KERNEL_PRESENT)
#include "FreeRTOS.h"
#include "task.h"
// Validate maximum of task registers
#if configNUM_SDK_THREAD_LOCAL_STORAGE_POINTERS > 255
#error "The task register API currently only supports a maximum of 255 registers"
#endif
// Check if the user has overwritten the configNUM_THREAD_LOCAL_STORAGE_POINTERS config
#if configNUM_THREAD_LOCAL_STORAGE_POINTERS < (configNUM_USER_THREAD_LOCAL_STORAGE_POINTERS \
+ configNUM_SDK_THREAD_LOCAL_STORAGE_POINTERS)
#error "Please use the configUSER_NUM_THREAD_LOCAL_STORAGE_POINTERS to configure the local storage pointers"
#endif
#elif defined(SL_CATALOG_MICRIUMOS_KERNEL_PRESENT)
#include "os.h"
#endif
#include "sl_status.h"
#include "cmsis_os2.h"
#ifdef __cplusplus
extern "C" {
#endif
#if defined(SL_CATALOG_FREERTOS_KERNEL_PRESENT)
typedef uint8_t sli_task_register_id_t;
#elif defined(SL_CATALOG_MICRIUMOS_KERNEL_PRESENT)
typedef OS_REG_ID sli_task_register_id_t;
#endif
/***************************************************************************//**
* Get the task register ID.
*
* @param[out] reg_id The task register id
* @return sl_status_t The status result
******************************************************************************/
sl_status_t sli_osTaskRegisterNew(sli_task_register_id_t *reg_id);
/***************************************************************************//**
* Get the task register value.
*
* @param thread_id CMSIS-RTOS2 thread identification
* @param reg_id Task register ID
* @param[out] value Value of the task register requested
* @return sl_status_t The status result
******************************************************************************/
sl_status_t sli_osTaskRegisterGetValue(const osThreadId_t thread_id,
const sli_task_register_id_t reg_id,
uint32_t *value);
/***************************************************************************//**
* Set the task register to the provided value.
*
* @param thread_id CMSIS-RTOS2 thread identification
* @param reg_id Task register ID
* @param[out] value Value of the task register to set
* @return sl_status_t The status result
******************************************************************************/
sl_status_t sli_osTaskRegisterSetValue(const osThreadId_t thread_id,
const sli_task_register_id_t reg_id,
const uint32_t value);
#ifdef __cplusplus
}
#endif
#endif // SLI_CMSIS_OS2_EXT_TASK_REGISTER_H

View File

@@ -0,0 +1,131 @@
/***************************************************************************//**
* @file
* @brief Code Classification API (Internal)
*******************************************************************************
* # License
* <b>Copyright 2023 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* 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.
*
******************************************************************************/
#ifndef _SLI_CODE_CLASSIFICATION_H_
#define _SLI_CODE_CLASSIFICATION_H_
// Standard Code Classes
#define SL_CODE_CLASS_TIME_CRITICAL timecritical
/******************************************************************************/
/* Helper Macros */
/******************************************************************************/
// Stringize tokens
#define _SL_CC_STRINGIZE(X) #X
#define _SL_CC_XSTRINGIZE(X) _SL_CC_STRINGIZE(X)
#define _SL_CC_CONCAT3(A, B, C) A B C
#define _SL_CC_CONCAT4(A, B, C, D) A B C D
/******************************************************************************/
/* Compiler Specific Macros */
/******************************************************************************/
// The directive that is built is dependent on the compiler. Section names are
// appended with an identifier generated from __COUNTER__ and __LINE__ so that
// functions are more likely to be separated into unique sections. Doing this
// allows the linker to discard unused functions with more granularity.
#if defined(__GNUC__) && !(defined(__llvm__) || defined(SLI_CODE_CLASSIFICATION_DISABLE))
// With GCC, __attribute__ can be used to specify the input section of
// functions.
#define _SL_CC_SECTION(section_name, count, line) \
__attribute__((section(_SL_CC_CONCAT3(_SL_CC_XSTRINGIZE(section_name), _SL_CC_XSTRINGIZE(count), _SL_CC_XSTRINGIZE(line)))))
#elif defined(__ICCARM__) && !defined(SLI_CODE_CLASSIFICATION_DISABLE)
// With IAR, _Pragma can be used to specify the input section of
// functions.
#define _SL_CC_SECTION(section_name, count, line) \
_Pragma(_SL_CC_XSTRINGIZE(_SL_CC_CONCAT4(location =, _SL_CC_XSTRINGIZE(section_name), _SL_CC_XSTRINGIZE(count), _SL_CC_XSTRINGIZE(line))))
#elif defined(__llvm__) && !defined(SLI_CODE_CLASSIFICATION_DISABLE)
// With llvm, __attribute__ can be used to specify the input section of
// functions.
// However the syntax of the string within the section directive is
// dependent on the specifics of the target backend (e.g. osx)
#if defined(__MACH__) && defined(SLI_CODE_CLASSIFICATION_OSX_ENABLE)
// code classifcation is not supported on OSX and can have weird
// interactions for executable code so it is disabled by default
// since it can be useful for code analysis allow it as an opt-in feature
#define _SL_CC_SECTION(section_name, count, line) \
__attribute__((section("sl_cc,code_class" _SL_CC_XSTRINGIZE(count) _SL_CC_XSTRINGIZE(line))))
#else
#define _SL_CC_SECTION(section_name, count, line)
#endif // defined(__MACH__)
#elif defined(SLI_CODE_CLASSIFICATION_DISABLE)
#define _SL_CC_SECTION(section_name, count, line)
#else
#error "(sli_code_classification.h): Code classification does not support \
the chosen compiler."
#endif // __GNUC__
/******************************************************************************/
/* Compiler Generic Macros */
/******************************************************************************/
// Build the linker section name based on the name of the component and the
// code classes.
#define _SL_CODE_CLASS_SECTION_CONCAT1(component, p1) \
text_ ## component ## _ ## p1
#define _SL_CODE_CLASS_SECTION_CONCAT2(component, p1, p2) \
text_ ## component ## _ ## p1 ## _ ## p2
// Build the compiler specific directives
#define _SL_CODE_CLASS1(component, c1) \
_SL_CC_SECTION(_SL_CODE_CLASS_SECTION_CONCAT1(component, c1), __COUNTER__, __LINE__)
#define _SL_CODE_CLASS2(component, c1, c2) \
_SL_CC_SECTION(_SL_CODE_CLASS_SECTION_CONCAT2(component, c1, c2), __COUNTER__, __LINE__)
// Utilities to dispatch a macro with the correct number of parameters.
// Update COUNT_N and COUNT macros if the upper limit of code class
// combinations increases.
#define _SL_CC_COUNT_N(_1, _2, N, ...) N
#define _SL_CC_COUNT(...) _SL_CC_COUNT_N(__VA_ARGS__, 2, 1)
#define _SL_CC_IDENTITY(N) N
#define _SL_CC_APPLY(macro, ...) _SL_CC_IDENTITY(macro(__VA_ARGS__))
// Dispatch _SL_CODE_CLASSX with the correct number of parameters.
#define _SL_CC_DISPATCH(N) _SL_CODE_CLASS ## N
/******************************************************************************/
/* Macro API (Internal) */
/******************************************************************************/
// Variadic macro to specify the code class membership of a function.
#define SL_CODE_CLASSIFY(component, ...) \
_SL_CC_IDENTITY(_SL_CC_APPLY(_SL_CC_DISPATCH, _SL_CC_COUNT(__VA_ARGS__)))(component, __VA_ARGS__)
#endif // _SLI_CODE_CLASSIFICATION_H_

View File

@@ -0,0 +1,76 @@
/***************************************************************************//**
* @file
* @brief Assert API
*******************************************************************************
* # License
* <b>Copyright 2021 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* 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 "sl_assert.h"
#include <stdbool.h>
/***************************************************************************//**
* @addtogroup assert
* @details
* This module contains functions to control the ASSERT peripheral of Silicon
* Labs 32-bit MCUs and SoCs.
* @{
******************************************************************************/
#if defined(DEBUG_EFM) && !defined(DEBUG_EFM_USER)
/***************************************************************************//**
* @brief
* EFM internal assert handling.
*
* This function is invoked through EFM_ASSERT() macro usage only and should
* not be used explicitly.
*
* This implementation enters an indefinite loop, allowing
* the use of a debugger to determine a cause of failure. By defining
* DEBUG_EFM_USER to the preprocessor for all files, a user-defined version
* of this function must be defined and will be invoked instead, possibly
* providing output of assertion location.
*
* @note
* This function is not used unless DEBUG_EFM is defined
* during preprocessing of EFM_ASSERT() usage.
*
* @param[in] file
* Name of the source file where assertion failed.
*
* @param[in] line
* A line number in the source file where assertion failed.
******************************************************************************/
void assertEFM(const char *file, int line)
{
(void)file; /* Unused parameter */
(void)line; /* Unused parameter */
while (true) {
}
}
#endif /* DEBUG_EFM && !DEBUG_EFM_USER */
/** @} (end addtogroup assert) */

View File

@@ -0,0 +1,61 @@
/***************************************************************************//**
* @file
* @brief CMSIS OS2 Common
*******************************************************************************
* # License
* <b>Copyright 2024 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* 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 <stddef.h>
#include "sl_assert.h"
#include "sl_status.h"
#include "cmsis_os2.h"
/***************************************************************************//**
* Convert OsStatus from CMSIS-RTOS2 to sl_status type.
******************************************************************************/
sl_status_t sl_cmsis_os_convert_status(osStatus_t os_status)
{
switch (os_status) {
case osOK:
return SL_STATUS_OK;
case osError:
return SL_STATUS_FAIL;
case osErrorTimeout:
return SL_STATUS_TIMEOUT;
case osErrorResource:
return SL_STATUS_NOT_AVAILABLE;
case osErrorParameter:
return SL_STATUS_INVALID_PARAMETER;
case osErrorNoMemory:
return SL_STATUS_NO_MORE_RESOURCE;
case osErrorISR:
return SL_STATUS_ISR;
case osStatusReserved:
default:
EFM_ASSERT(0);
return SL_STATUS_FAIL;
}
}

View File

@@ -0,0 +1,395 @@
/***************************************************************************//**
* @file
* @brief Core API implemented for CortexM
*******************************************************************************
* # License
* <b>Copyright 2024 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* 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 "sl_core.h"
#include "sl_core_config.h"
#include "sl_common.h"
#include "em_device.h"
/**************************************************************************//**
* @addtogroup sl_core
* @{
*****************************************************************************/
/*******************************************************************************
************************** STRUCTS ****************************************
******************************************************************************/
/// A Cycle Counter Instance.
typedef struct {
uint32_t start; /*!< Cycle counter at start of recording. */
uint32_t cycles; /*!< Cycles elapsed in last recording. */
uint32_t max; /*!< Max recorded cycles since last reset or init. */
} dwt_cycle_counter_handle_t;
/*******************************************************************************
*************************** LOCAL VARIABLES *******************************
******************************************************************************/
/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
#if (SL_CORE_DEBUG_INTERRUPTS_MASKED_TIMING == 1)
// cycle counter to record atomic sections
dwt_cycle_counter_handle_t atomic_cycle_counter = { 0 };
// cycle counter to record critical sections
dwt_cycle_counter_handle_t critical_cycle_counter = { 0 };
#endif
/** @endcond */
/*******************************************************************************
*************************** LOCAL FUNCTIONS *******************************
******************************************************************************/
#if (SL_CORE_DEBUG_INTERRUPTS_MASKED_TIMING == 1)
static void cycle_counter_start(dwt_cycle_counter_handle_t *handle);
static void cycle_counter_stop(dwt_cycle_counter_handle_t *handle);
#endif
/*******************************************************************************
************************** GLOBAL FUNCTIONS *******************************
******************************************************************************/
/***************************************************************************//**
* @brief
* Disable interrupts.
******************************************************************************/
SL_WEAK void CORE_CriticalDisableIrq(void)
{
__disable_irq();
}
/***************************************************************************//**
* @brief
* Enable interrupts.
* @note
* __ISB() makes sure pending interrupts are executed before returning.
* This can be a problem if the first instruction after changing the BASEPRI
* or PRIMASK assumes that the pending interrupts have already been processed.
******************************************************************************/
SL_WEAK void CORE_CriticalEnableIrq(void)
{
__enable_irq();
__ISB();
}
/***************************************************************************//**
* @brief
* Enter a CRITICAL section.
******************************************************************************/
SL_WEAK CORE_irqState_t CORE_EnterCritical(void)
{
CORE_irqState_t irqState = __get_PRIMASK();
__disable_irq();
#if (SL_CORE_DEBUG_INTERRUPTS_MASKED_TIMING == 1)
if (irqState == 0U) {
cycle_counter_start(&critical_cycle_counter);
}
#endif
return irqState;
}
/***************************************************************************//**
* @brief
* Exit a CRITICAL section.
* @note
* __ISB() makes sure pending interrupts are executed before returning.
* This can be a problem if the first instruction after changing the BASEPRI
* or PRIMASK assumes that the pending interrupts have already been processed.
******************************************************************************/
SL_WEAK void CORE_ExitCritical(CORE_irqState_t irqState)
{
if (irqState == 0U) {
#if (SL_CORE_DEBUG_INTERRUPTS_MASKED_TIMING == 1)
cycle_counter_stop(&critical_cycle_counter);
#endif
__enable_irq();
__ISB();
}
}
/***************************************************************************//**
* @brief
* Brief interrupt enable/disable sequence to allow handling of
* pending interrupts.
******************************************************************************/
SL_WEAK void CORE_YieldCritical(void)
{
if ((__get_PRIMASK() & 1U) != 0U) {
__enable_irq();
__ISB();
__disable_irq();
}
}
/***************************************************************************//**
* @brief
* Disable interrupts.
******************************************************************************/
SL_WEAK void CORE_AtomicDisableIrq(void)
{
#ifndef __CM0PLUS_REV
__set_BASEPRI(CORE_ATOMIC_BASE_PRIORITY_LEVEL << (8UL - __NVIC_PRIO_BITS));
#else
__disable_irq();
#endif
}
/***************************************************************************//**
* @brief
* Enable interrupts.
* @note
* __ISB() makes sure pending interrupts are executed before returning.
* This can be a problem if the first instruction after changing the BASEPRI
* or PRIMASK assumes that the pending interrupts have already been processed.
******************************************************************************/
SL_WEAK void CORE_AtomicEnableIrq(void)
{
#ifndef __CM0PLUS_REV
__set_BASEPRI(0);
#else
__enable_irq();
#endif
__ISB();
}
/***************************************************************************//**
* @brief
* Enter an ATOMIC section.
******************************************************************************/
SL_WEAK CORE_irqState_t CORE_EnterAtomic(void)
{
#ifndef __CM0PLUS_REV
CORE_irqState_t irqState = __get_BASEPRI();
__set_BASEPRI(CORE_ATOMIC_BASE_PRIORITY_LEVEL << (8U - __NVIC_PRIO_BITS));
#if (SL_CORE_DEBUG_INTERRUPTS_MASKED_TIMING == 1)
if ((irqState & (CORE_ATOMIC_BASE_PRIORITY_LEVEL << (8U - __NVIC_PRIO_BITS)))
!= (CORE_ATOMIC_BASE_PRIORITY_LEVEL << (8U - __NVIC_PRIO_BITS))) {
cycle_counter_start(&atomic_cycle_counter);
}
#endif
return irqState;
#else
CORE_irqState_t irqState = __get_PRIMASK();
__disable_irq();
#if (SL_CORE_DEBUG_INTERRUPTS_MASKED_TIMING == 1)
if (irqState == 0U) {
cycle_counter_start(&critical_cycle_counter);
}
#endif
return irqState;
#endif
}
/***************************************************************************//**
* @brief
* Exit an ATOMIC section.
* @note
* __ISB() makes sure pending interrupts are executed before returning.
* This can be a problem if the first instruction after changing the BASEPRI
* or PRIMASK assumes that the pending interrupts have already been processed.
******************************************************************************/
SL_WEAK void CORE_ExitAtomic(CORE_irqState_t irqState)
{
#ifndef __CM0PLUS_REV
#if (SL_CORE_DEBUG_INTERRUPTS_MASKED_TIMING == 1)
if ((irqState & (CORE_ATOMIC_BASE_PRIORITY_LEVEL << (8U - __NVIC_PRIO_BITS)))
!= (CORE_ATOMIC_BASE_PRIORITY_LEVEL << (8U - __NVIC_PRIO_BITS))) {
cycle_counter_stop(&atomic_cycle_counter);
}
#endif
__set_BASEPRI(irqState);
__ISB();
#else
if (irqState == 0U) {
#if (SL_CORE_DEBUG_INTERRUPTS_MASKED_TIMING == 1)
cycle_counter_stop(&critical_cycle_counter);
#endif
__enable_irq();
__ISB();
}
#endif
}
/***************************************************************************//**
* @brief
* Brief interrupt enable/disable sequence to allow handling of
* pending interrupts.
******************************************************************************/
SL_WEAK void CORE_YieldAtomic(void)
{
#ifndef __CM0PLUS_REV
CORE_irqState_t basepri = __get_BASEPRI();
if (basepri >= (CORE_ATOMIC_BASE_PRIORITY_LEVEL << (8U - __NVIC_PRIO_BITS))) {
__set_BASEPRI(0);
__ISB();
__set_BASEPRI(basepri);
}
#else
if ((__get_PRIMASK() & 1U) != 0U) {
__enable_irq();
__ISB();
__disable_irq();
}
#endif
}
/***************************************************************************//**
* @brief
* Check whether the current CPU operation mode is handler mode.
******************************************************************************/
SL_WEAK bool CORE_InIrqContext(void)
{
return (SCB->ICSR & SCB_ICSR_VECTACTIVE_Msk) != 0U;
}
/***************************************************************************//**
* @brief
* Check if interrupts are disabled.
******************************************************************************/
SL_WEAK bool CORE_IrqIsDisabled(void)
{
#ifndef __CM0PLUS_REV
return ((__get_PRIMASK() & 1U) == 1U)
|| (__get_BASEPRI() >= (CORE_ATOMIC_BASE_PRIORITY_LEVEL
<< (8U - __NVIC_PRIO_BITS)));
#else
return (__get_PRIMASK() & 1U == 1U);
#endif
}
#if (SL_CORE_DEBUG_INTERRUPTS_MASKED_TIMING == 1)
/***************************************************************************//**
* @brief
* Start a recording.
*
* @param[in] handle
* Pointer to initialized counter handle.
*
* @note SL_CORE_DEBUG_INTERRUPTS_MASKED_TIMING must be enabled.
******************************************************************************/
static void cycle_counter_start(dwt_cycle_counter_handle_t *handle)
{
handle->start = DWT->CYCCNT;
}
#endif //(SL_CORE_DEBUG_INTERRUPTS_MASKED_TIMING == 1)
#if (SL_CORE_DEBUG_INTERRUPTS_MASKED_TIMING == 1)
/***************************************************************************//**
* @brief
* Stop a recording.
*
* @param[in] handle
* Pointer to initialized counter handle.
*
* @note SL_CORE_DEBUG_INTERRUPTS_MASKED_TIMING must be enabled.
******************************************************************************/
static void cycle_counter_stop(dwt_cycle_counter_handle_t *handle)
{
handle->cycles = DWT->CYCCNT - handle->start;
if (handle->cycles > handle->max) {
handle->max = handle->cycles;
}
}
#endif //(SL_CORE_DEBUG_INTERRUPTS_MASKED_TIMING == 1)
/***************************************************************************//**
* @brief
* Returns the max time spent in critical section.
******************************************************************************/
uint32_t CORE_get_max_time_critical_section(void)
{
#if (SL_CORE_DEBUG_INTERRUPTS_MASKED_TIMING == 1)
return critical_cycle_counter.max;
#else
return 0U;
#endif //(SL_CORE_DEBUG_INTERRUPTS_MASKED_TIMING == 1)
}
/***************************************************************************//**
* @brief
* Returns the max time spent in atomic section.
******************************************************************************/
uint32_t CORE_get_max_time_atomic_section(void)
{
#if (SL_CORE_DEBUG_INTERRUPTS_MASKED_TIMING == 1)
return atomic_cycle_counter.max;
#else
return 0U;
#endif //(SL_CORE_DEBUG_INTERRUPTS_MASKED_TIMING == 1)
}
/***************************************************************************//**
* @brief
* Clears the max time spent in atomic section.
******************************************************************************/
void CORE_clear_max_time_critical_section(void)
{
#if (SL_CORE_DEBUG_INTERRUPTS_MASKED_TIMING == 1)
critical_cycle_counter.max = 0;
#endif //(SL_CORE_DEBUG_INTERRUPTS_MASKED_TIMING == 1)
}
/***************************************************************************//**
* @brief
* Clears the max time spent in atomic section.
******************************************************************************/
void CORE_clear_max_time_atomic_section(void)
{
#if (SL_CORE_DEBUG_INTERRUPTS_MASKED_TIMING == 1)
atomic_cycle_counter.max = 0;
#endif //(SL_CORE_DEBUG_INTERRUPTS_MASKED_TIMING == 1)
}
/***************************************************************************//**
* @brief
* Reset chip routine.
******************************************************************************/
void CORE_ResetSystem(void)
{
// Ensure all outstanding memory accesses including buffered writes are
// completed before reset
__DSB();
// Keep priority group unchanged
SCB->AIRCR = (0x5FAUL << SCB_AIRCR_VECTKEY_Pos)
| (SCB->AIRCR & SCB_AIRCR_PRIGROUP_Msk)
| SCB_AIRCR_SYSRESETREQ_Msk;
// Ensure completion of memory access
__DSB();
// Wait until reset
for (;; ) {
__NOP();
}
}
/** @} (end addtogroup sl_core) */

View File

@@ -0,0 +1,190 @@
/***************************************************************************//**
* @file
* @brief Single Link List
*******************************************************************************
* # License
* <b>Copyright 2019 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* 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 "sl_assert.h"
#include "sl_slist.h"
#include <stdbool.h>
#include <stdlib.h>
#include <stdint.h>
/*******************************************************************************
************************** GLOBAL FUNCTIONS *******************************
******************************************************************************/
/***************************************************************************//**
* Initializes a singly-linked list.
******************************************************************************/
void sl_slist_init(sl_slist_node_t **head)
{
*head = 0;
}
/***************************************************************************//**
* Add given item at beginning of list.
******************************************************************************/
void sl_slist_push(sl_slist_node_t **head,
sl_slist_node_t *item)
{
EFM_ASSERT((item != NULL) && (head != NULL));
item->node = *head;
*head = item;
}
/***************************************************************************//**
* Add item at end of list.
******************************************************************************/
void sl_slist_push_back(sl_slist_node_t **head,
sl_slist_node_t *item)
{
sl_slist_node_t **node_ptr = head;
EFM_ASSERT((item != NULL) && (head != NULL));
while (*node_ptr != NULL) {
node_ptr = &((*node_ptr)->node);
}
item->node = NULL;
*node_ptr = item;
}
/***************************************************************************//**
* Removes and returns first element of list.
******************************************************************************/
sl_slist_node_t *sl_slist_pop(sl_slist_node_t **head)
{
sl_slist_node_t *item;
EFM_ASSERT(head != NULL);
item = *head;
if (item == NULL) {
return (NULL);
}
*head = item->node;
item->node = NULL;
return (item);
}
/***************************************************************************//**
* Insert item after given item.
******************************************************************************/
void sl_slist_insert(sl_slist_node_t *item,
sl_slist_node_t *pos)
{
EFM_ASSERT((item != NULL) && (pos != NULL));
item->node = pos->node;
pos->node = item;
}
/***************************************************************************//**
* Add item at end of list.
******************************************************************************/
void sl_slist_join(sl_slist_node_t **head_list_1,
sl_slist_node_t **head_list_2)
{
sl_slist_node_t **node_ptr = head_list_1;
EFM_ASSERT((head_list_2 != NULL)
&& (head_list_1 != NULL));
while (*node_ptr != NULL) {
node_ptr = &((*node_ptr)->node);
}
*node_ptr = *head_list_2;
*head_list_2 = NULL;
}
/***************************************************************************//**
* Remove item from list.
******************************************************************************/
void sl_slist_remove(sl_slist_node_t **head,
sl_slist_node_t *item)
{
sl_slist_node_t **node_ptr;
EFM_ASSERT((item != NULL) && (head != NULL));
for (node_ptr = head; *node_ptr != NULL; node_ptr = &((*node_ptr)->node)) {
if (*node_ptr == item) {
*node_ptr = item->node;
item->node = NULL;
return;
}
}
}
/***************************************************************************//**
* Sorts list items.
******************************************************************************/
void sl_slist_sort(sl_slist_node_t **head,
bool (*cmp_fnct)(sl_slist_node_t *item_l,
sl_slist_node_t *item_r))
{
bool swapped;
sl_slist_node_t **pp_item_l;
EFM_ASSERT((head != NULL) && (cmp_fnct != NULL));
do {
swapped = false;
pp_item_l = head;
// Loop until end of list is found.
while ((*pp_item_l != NULL) && ((*pp_item_l)->node != NULL)) {
sl_slist_node_t *p_item_r = (*pp_item_l)->node;
bool ordered;
// Call provided compare fnct.
ordered = cmp_fnct(*pp_item_l, p_item_r);
if (ordered == false) {
// If order is not correct, swap items.
sl_slist_node_t *p_tmp = p_item_r->node;
// Swap the two items.
p_item_r->node = *pp_item_l;
(*pp_item_l)->node = p_tmp;
*pp_item_l = p_item_r;
pp_item_l = &(p_item_r->node);
// Indicate a swap has been done.
swapped = true;
} else {
pp_item_l = &((*pp_item_l)->node);
}
}
// Re-loop until no items have been swapped.
} while (swapped == true);
}

View File

@@ -0,0 +1,115 @@
/***************************************************************************//**
* @file
* @brief SystemCall API
*******************************************************************************
* # License
* <b>Copyright 2023 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* 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.
*
******************************************************************************/
/***************************************************************************//**
* @addtogroup systemcalls
* @details
* This module reimplements the syscalls that don't have the definition in the
* bare metal project.
* This prevents linker warnings.
* @{
******************************************************************************/
#include "sl_compiler.h"
struct stat;
struct timeval;
struct timezone;
__WEAK int _close(int file)
{
(void)file;
return -1;
}
__WEAK void _exit(int status)
{
(void)status;
/* Convince GCC that this function never returns. */
for (;; ) {
;
}
}
__WEAK int _fstat(int file, struct stat *st)
{
(void)file;
(void)(void *)st;
return 0;
}
__WEAK int _getpid(void)
{
return 1;
}
__WEAK int _isatty(int file)
{
(void)file;
return 1;
}
__WEAK int _kill(int pid, int sig)
{
(void)pid;
(void)sig;
return -1;
}
__WEAK int _lseek(int file, int ptr, int dir)
{
(void)file;
(void)ptr;
(void)dir;
return 0;
}
__WEAK int _read(int file, char *ptr, int len)
{
(void)file;
(void)(void *)ptr;
(void)len;
return 0;
}
__WEAK int _write(int file, const char *ptr, int len)
{
(void)file;
(void)(const void *)ptr;
(void)len;
return 0;
}
__WEAK int _gettimeofday(struct timeval *tv, struct timezone *tz)
{
(void)(void *)tv;
(void)(void *)tz;
return 0;
}

View File

@@ -0,0 +1,143 @@
/***************************************************************************//**
* @file sli_cmsis_os2_ext_task_register.c
* @brief Abstraction for Task Registers (Thread Local Variables)
*******************************************************************************
* # License
* <b>Copyright 2020 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* 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 "sl_assert.h"
#include "sli_cmsis_os2_ext_task_register.h"
#include "sl_cmsis_os2_common.h"
/*******************************************************************************
*************************** LOCAL VARIABLES ********************************
******************************************************************************/
/*******************************************************************************
************************** GLOBAL FUNCTIONS *******************************
******************************************************************************/
/***************************************************************************//**
* Get a task register ID
******************************************************************************/
sl_status_t sli_osTaskRegisterNew(sli_task_register_id_t *reg_id)
{
sl_status_t status = SL_STATUS_FAIL;
if (reg_id == NULL) {
return SL_STATUS_FAIL;
}
#if defined(SL_CATALOG_MICRIUMOS_KERNEL_PRESENT)
RTOS_ERR err;
*reg_id = OSTaskRegGetID(&err);
if (RTOS_ERR_CODE_GET(err) == RTOS_ERR_NONE) {
status = SL_STATUS_OK;
}
#elif defined(SL_CATALOG_FREERTOS_KERNEL_PRESENT)
static uint8_t register_count = 0;
if (register_count > (configNUM_SDK_THREAD_LOCAL_STORAGE_POINTERS - 1)) {
return SL_STATUS_FAIL;
}
*reg_id = register_count + configNUM_USER_THREAD_LOCAL_STORAGE_POINTERS;
++register_count;
status = SL_STATUS_OK;
#else
#error "Task registers abstraction only supports MicriumOS or FreeRTOS"
#endif
return status;
}
/***************************************************************************//**
* Get the task register
******************************************************************************/
sl_status_t sli_osTaskRegisterGetValue(const osThreadId_t thread_id,
const sli_task_register_id_t reg_id,
uint32_t *value)
{
sl_status_t status = SL_STATUS_FAIL;
#if defined(SL_CATALOG_MICRIUMOS_KERNEL_PRESENT)
RTOS_ERR err;
osThread_t *thread;
if (value == NULL) {
return SL_STATUS_FAIL;
}
if (thread_id != NULL) {
thread = (osThread_t *)thread_id;
*value = OSTaskRegGet(&thread->tcb, reg_id, &err);
} else {
*value = OSTaskRegGet(NULL, reg_id, &err);
}
if (RTOS_ERR_CODE_GET(err) == RTOS_ERR_NONE) {
status = SL_STATUS_OK;
}
#elif defined(SL_CATALOG_FREERTOS_KERNEL_PRESENT)
*value = (uint32_t)pvTaskGetThreadLocalStoragePointer(thread_id, reg_id);
status = SL_STATUS_OK;
#else
#error "Task registers abstraction only supports MicriumOS or FreeRTOS"
#endif
return status;
}
/***************************************************************************//**
* Set the task register
******************************************************************************/
sl_status_t sli_osTaskRegisterSetValue(const osThreadId_t thread_id,
const sli_task_register_id_t reg_id,
const uint32_t value)
{
sl_status_t status = SL_STATUS_FAIL;
#if defined(SL_CATALOG_MICRIUMOS_KERNEL_PRESENT)
RTOS_ERR err;
osThread_t *thread;
if (thread_id != NULL) {
thread = (osThread_t *)thread_id;
OSTaskRegSet(&thread->tcb, reg_id, (OS_REG)value, &err);
} else {
OSTaskRegSet(NULL, reg_id, (OS_REG)value, &err);
}
if (RTOS_ERR_CODE_GET(err) == RTOS_ERR_NONE) {
status = SL_STATUS_OK;
}
#elif defined(SL_CATALOG_FREERTOS_KERNEL_PRESENT)
vTaskSetThreadLocalStoragePointer(thread_id, reg_id, (void *)value);
status = SL_STATUS_OK;
#else
#error "Task registers abstraction only supports MicriumOS or FreeRTOS"
#endif
return status;
}

View File

@@ -0,0 +1,40 @@
/***************************************************************************//**
* @file
* @brief GCC startup file
*******************************************************************************
* # License
* <b>Copyright 2023 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* 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.
*
******************************************************************************/
/* The startup files contain a stack and heap symbol in addition
* to the vector table. The size of these internal stack and heap
* objects depend on the build system providing two macros on the
* commandline called __STACK_SIZE and __HEAP_SIZE.
*
* We provide alternative stack and heap symbols in the sl_memory_region.c
* file which can be configured in a separate config file. Go to
* sl_memory_manager_config.h to configure the stack and heap size. */
#define __STACK_SIZE 0x0
#define __HEAP_SIZE 0x0

View File

@@ -0,0 +1,39 @@
/***************************************************************************//**
* @file
* @brief Heap and stack memory
*******************************************************************************
* # License
* <b>Copyright 2020 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* 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.
*
******************************************************************************/
#ifndef SL_MEMORY_H
#define SL_MEMORY_H
#include "sl_memory_manager_region.h"
#ifndef SL_SUPPRESS_DEPRECATION_WARNINGS_SDK_2024_6
#warning "This file is deprecated as of Simplicity SDK 2024.6. Content was moved to sl_memory_manager.h."
#endif
#endif // SL_MEMORY_H

View File

@@ -0,0 +1,39 @@
/***************************************************************************//**
* @file
* @brief Memory region types
*******************************************************************************
* # License
* <b>Copyright 2024 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* 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.
*
******************************************************************************/
#ifndef SL_REGION_H
#define SL_REGION_H
#include "sl_memory_manager_region.h"
#ifndef SL_SUPPRESS_DEPRECATION_WARNINGS_SDK_2024_6
#warning "This file is deprecated as of Simplicity SDK 2024.6. Content was moved to sl_memory_manager.h."
#endif
#endif

View File

@@ -0,0 +1,191 @@
/***************************************************************************//**
* @file
* @brief Button Driver
*******************************************************************************
* # License
* <b>Copyright 2019 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* 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.
*
******************************************************************************/
#ifndef SL_BUTTON_H
#define SL_BUTTON_H
#include "sl_common.h"
#include "sl_status.h"
#ifdef __cplusplus
extern "C" {
#endif
/***************************************************************************//**
* @addtogroup button Button API
* @brief Generic Button API
* @{
******************************************************************************/
/*******************************************************************************
****************************** DEFINES ************************************
******************************************************************************/
#define BUTTON_ERROR 0xFFFF ///< Error when trying to return state
/*******************************************************************************
***************************** DATA TYPES *********************************
******************************************************************************/
typedef uint8_t sl_button_mode_t; ///< BUTTON mode
typedef uint8_t sl_button_state_t; ///< BUTTON state
typedef struct sl_button sl_button_t; ///< BUTTON Instance structure
/// A BUTTON instance
typedef struct sl_button {
void *context; ///< The context for this BUTTON instance
sl_status_t (*init)(const sl_button_t *handle); ///< Member function to initialize BUTTON instance
void (*poll)(const sl_button_t *handle); ///< Member function to poll BUTTON
void (*enable)(const sl_button_t *handle); ///< Member function to enable BUTTON
void (*disable)(const sl_button_t *handle); ///< Member function to disable BUTTON
sl_button_state_t (*get_state)(const sl_button_t *handle); ///< Member function to retrieve BUTTON state
} sl_button;
/*******************************************************************************
***************************** PROTOTYPES **********************************
******************************************************************************/
/***************************************************************************//**
* Button driver init. This function should be called before calling any other
* button function. Sets up the GPIO. Sets the mode of operation. Sets up the
* interrupts based on the mode of operation.
*
* @param[in] handle Pointer to button instance
*
* @return Status Code:
* - SL_STATUS_OK
******************************************************************************/
sl_status_t sl_button_init(const sl_button_t *handle);
/***************************************************************************//**
* Get button state.
*
* @param[in] handle Pointer to button instance
*
* @return Button state Current state of the button
******************************************************************************/
sl_button_state_t sl_button_get_state(const sl_button_t *handle);
/***************************************************************************//**
* Enable the button.
*
* @param[in] handle Pointer to button instance
*
******************************************************************************/
void sl_button_enable(const sl_button_t *handle);
/***************************************************************************//**
* Disable the button.
*
* @param[in] handle Pointer to button instance
*
******************************************************************************/
void sl_button_disable(const sl_button_t *handle);
/***************************************************************************//**
* Poll the button.
*
* @param[in] handle Pointer to button instance
******************************************************************************/
void sl_button_poll_step(const sl_button_t *handle);
/***************************************************************************//**
* A callback called in interrupt context whenever a button changes its state.
*
* @remark Can be implemented by the application if required. This function
* can contain the functionality to be executed in response to changes of state
* in each of the buttons, or callbacks to appropriate functionality.
*
* @note The button state should not be updated in this function, it is updated
* by specific button driver prior to arriving here
*
@param[out] handle Pointer to button instance
******************************************************************************/
void sl_button_on_change(const sl_button_t *handle);
/** @} (end addtogroup button) */
// ******** THE REST OF THE FILE IS DOCUMENTATION ONLY !***********************
/// @addtogroup button Button API
/// @{
///
/// @details
///
/// @n @section buttondrv_intro Introduction
///
/// The button driver is a platfom level software module that manages the initialization
/// and reading of various types of buttons. There is currently one type of button
/// supported by the button driver:
///
/// @li @ref simple_button
///
/// All button functions are called through the generic driver, which then references
/// functions in the simple button and other potential future button drivers.
///
/// @n @section buttondrv_config Configuration
///
/// All button instances are configured with an @ref sl_button_t struct and a type specific
/// context struct. These structs are automatically generated after a button is set up
/// using Simplicity Studio's wizard, along with a function definition for initializing all
/// LEDs of that type. Specific setup for the simple button is in the following section.
///
/// - [Simple Button Configuration](/gecko-platform/<docspace-docleaf-version>/platform-driver/simple-button#simple-button-configuration)
///
/// @n @section buttondrv_usage Usage
///
/// Once the button structs are defined, the common button functions can be called being
/// passed an instance of sl_button_t, which will be redirected to calling the type specific
/// version of that function. The common functions include the following:
///
/// @li @ref sl_button_init
/// @li @ref sl_button_get_state
/// @li @ref sl_button_poll_step
/// @li @ref sl_button_on_change
///
/// @ref sl_button_init must be called before attempting to read the state of the button.
///
/// The button driver can either be used with interrupt mode, polling or polling with debounce.
/// In the case of using interrupt mode, @ref sl_button_on_change can be implemented by the
/// application if required. This function can contain functionality to be executed in response
/// to button event or callbacks to appropriate functionality.
/// In the case of polling and polling with debounce mode, @ref sl_button_poll_step is used to
/// update the state, and needs to be called from a tick function or similar by the user.
/// These mode can be configured per button instance in the instance specific config file.
///
/// Both the interrupt and polling methods obtain the button state for the user by calling
/// @ref sl_button_get_state.
///
/// @} end group button ********************************************************/
#ifdef __cplusplus
}
#endif
#endif // SL_BUTTON_H

View File

@@ -0,0 +1,225 @@
/***************************************************************************//**
* @file
* @brief Simple Button Driver
*******************************************************************************
* # License
* <b>Copyright 2019 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* 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.
*
******************************************************************************/
#ifndef SL_SIMPLE_BUTTON_H
#define SL_SIMPLE_BUTTON_H
#include "sl_button.h"
#include "sl_gpio.h"
#ifdef __cplusplus
extern "C" {
#endif
/***************************************************************************//**
* @addtogroup button
* @{
******************************************************************************/
/***************************************************************************//**
* @addtogroup simple_button Simple Button Driver
* @details Simple Button Driver module provides APIs to initalize and read
* simple buttons. Subsequent sections provide more insight into button
* driver configuration and usage.
* @{
******************************************************************************/
/*******************************************************************************
****************************** DEFINES ************************************
******************************************************************************/
#define SL_SIMPLE_BUTTON_MODE_POLL 0U ///< BUTTON input capture using polling
#define SL_SIMPLE_BUTTON_MODE_POLL_AND_DEBOUNCE 1U ///< BUTTON input capture using polling and debouncing
#define SL_SIMPLE_BUTTON_MODE_INTERRUPT 2U ///< BUTTON input capture using interrupt
#define SL_SIMPLE_BUTTON_DISABLED 2U ///< BUTTON state is disabled
#define SL_SIMPLE_BUTTON_PRESSED 1U ///< BUTTON state is pressed
#define SL_SIMPLE_BUTTON_RELEASED 0U ///< BUTTON state is released
#define SL_SIMPLE_BUTTON_GET_STATE(context) (((sl_simple_button_context_t *)(context))->state) ///< BUTTON member function to get state
#define SL_SIMPLE_BUTTON_GET_PORT(context) (((sl_simple_button_context_t *)(context))->port) ///< BUTTON member function to get port
#define SL_SIMPLE_BUTTON_GET_PIN(context) (((sl_simple_button_context_t *)(context))->pin) ///< BUTTON member function to get pin
#define SL_SIMPLE_BUTTON_GET_MODE(context) (((sl_simple_button_context_t *)(context))->mode) ///< BUTTON member function to get mode
/*******************************************************************************
***************************** DATA TYPES *********************************
******************************************************************************/
/// A Simple BUTTON instance
typedef struct {
sl_button_state_t state; ///< Current button state
uint16_t history; ///< History of button states
sl_gpio_port_t port; ///< Button port
uint8_t pin; ///< Button pin
sl_button_mode_t mode; ///< Mode of operation
} sl_simple_button_context_t;
/*******************************************************************************
***************************** PROTOTYPES **********************************
******************************************************************************/
/***************************************************************************//**
* Initialize the simple button driver.
*
* @param[in] handle Pointer to button handle:
* - sl_button_t
*
* @return Status Code:
* - SL_STATUS_OK
******************************************************************************/
sl_status_t sl_simple_button_init(const sl_button_t *handle);
/***************************************************************************//**
* Get the current state of the simple button.
*
* @param[in] handle Pointer to button handle:
* - sl_button_t
*
* @return Button State: Current state of the button
* - SL_SIMPLE_BUTTON_PRESSED
* - SL_SIMPLE_BUTTON_RELEASED
******************************************************************************/
sl_button_state_t sl_simple_button_get_state(const sl_button_t *handle);
/***************************************************************************//**
* Poll the simple button. (button mode - poll / poll and debonuce)
*
* @param[in] handle Pointer to button handle:
* - sl_button_t
******************************************************************************/
void sl_simple_button_poll_step(const sl_button_t *handle);
/***************************************************************************//**
* Enable the simple button.
*
* @param[in] handle Pointer to button handle:
* - sl_button_t
******************************************************************************/
void sl_simple_button_enable(const sl_button_t *handle);
/***************************************************************************//**
* Disable the simple button.
*
* @param[in] handle Pointer to button handle:
* - sl_button_t
******************************************************************************/
void sl_simple_button_disable(const sl_button_t *handle);
/** @} (end addtogroup simple_button) */
/** @} (end addtogroup button) */
// ******** THE REST OF THE FILE IS DOCUMENTATION ONLY !***********************
/// @addtogroup simple_button Simple Button Driver
/// @{
///
/// @details
///
///
/// @n @section simple_button_intro Introduction
///
/// The Simple Button driver is a module of the button driver that provides the functionality
/// to initialize and read simple buttons.
///
/// @n @section simple_button_config Simple Button Configuration
///
/// Simple buttons use the @ref sl_button_t struct and their @ref sl_simple_button_context_t
/// struct. These are automatically generated into the following files, as well as
/// instance specific headers with macro definitions in them. The samples below
/// are for a single instance called "inst0".
///
/// @code{.c}
///// sl_simple_button_instances.c
///
///#include "sl_simple_button.h"
///#include "sl_simple_button_inst0_config.h"
///
///sl_simple_button_context_t simple_inst0_context = {
/// .state = 0,
/// .history = 0,
/// .port = SL_SIMPLE_BUTTON_INST0_PORT,
/// .pin = SL_SIMPLE_BUTTON_INST0_PIN,
/// .mode = SL_SIMPLE_BUTTON_INST0_MODE,
///};
///
///const sl_button_t sl_button_inst0 = {
/// .context = &simple_inst0_context,
/// .init = sl_simple_button_init,
/// .get_state = sl_simple_button_get_state,
/// .poll = sl_simple_button_poll_step,
///};
///
///const sl_button_t *sl_simple_button_array[] = {&sl_button_inst0};
///const uint8_t simple_button_count = 1;
///
///void sl_simple_button_init_instances(void)
///{
/// sl_button_init(&sl_button_inst0);
///}
///
///void sl_simple_button_poll_instances(void)
///{
/// sl_button_poll_step(&sl_button_inst0);
///}
/// @endcode
///
/// @note The sl_simple_button_instances.c file is shown with only one instance, but if more
/// were in use they would all appear in this .c file.
///
/// @code{.c}
///// sl_simple_button_instances.h
///
///#ifndef SL_SIMPLE_BUTTON_INSTANCES_H
///#define SL_SIMPLE_BUTTON_INSTANCES_H
///
///#include "sl_simple_button.h"
///
///extern const sl_button_t sl_button_inst0;
///
///void sl_simple_button_init_instances(void);
///void sl_simple_button_poll_instances(void);
///
///#endif // SL_SIMPLE_BUTTON_INSTANCES_H
/// @endcode
///
/// @note The sl_simple_button_instances.h file is shown with only one instance, but if more
/// were in use they would all appear in this .h file.
///
/// @n @section simple_button_usage Simple Button Usage
///
/// The simple button driver has no differences in its usage from the common button driver.
/// See @ref buttondrv_usage.
///
/// @} end group simple_button ********************************************************/
#ifdef __cplusplus
}
#endif
#endif // SL_SIMPLE_BUTTON_H

View File

@@ -0,0 +1,76 @@
/***************************************************************************//**
* @file
* @brief Button Driver
*******************************************************************************
* # License
* <b>Copyright 2019 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* 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 "sl_button.h"
#include <stddef.h>
sl_status_t sl_button_init(const sl_button_t *handle)
{
if (handle->init != NULL) {
return handle->init(handle);
} else {
return SL_STATUS_NULL_POINTER;
}
}
sl_button_state_t sl_button_get_state(const sl_button_t *handle)
{
if (handle->get_state != NULL) {
return handle->get_state(handle);
} else {
return (sl_button_state_t)BUTTON_ERROR;
}
}
void sl_button_poll_step(const sl_button_t *handle)
{
if (handle->poll != NULL) {
handle->poll(handle);
}
}
void sl_button_enable(const sl_button_t *handle)
{
if (handle->enable != NULL) {
handle->enable(handle);
}
}
void sl_button_disable(const sl_button_t *handle)
{
if (handle->disable != NULL) {
handle->disable(handle);
}
}
SL_WEAK void sl_button_on_change(const sl_button_t *handle)
{
(void)handle;
}

View File

@@ -0,0 +1,205 @@
/***************************************************************************//**
* @file
* @brief Simple Button Driver
*******************************************************************************
* # License
* <b>Copyright 2019 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* 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 "sl_simple_button.h"
#include "sl_simple_button_config.h"
#include "sl_clock_manager.h"
#if (SL_SIMPLE_BUTTON_DEBOUNCE_BITS < 1U)
#undef SL_SIMPLE_BUTTON_DEBOUNCE_BITS
#define SL_SIMPLE_BUTTON_DEBOUNCE_BITS 1U
#endif
#if (SL_SIMPLE_BUTTON_DEBOUNCE_BITS > 15U)
#undef SL_SIMPLE_BUTTON_DEBOUNCE_BITS
#define SL_SIMPLE_BUTTON_DEBOUNCE_BITS 15U
#endif
static const uint16_t check_press = (uint16_t)(0xffff << SL_SIMPLE_BUTTON_DEBOUNCE_BITS);
static const uint16_t check_release = (uint16_t)(~(0x1 << SL_SIMPLE_BUTTON_DEBOUNCE_BITS));
static const uint16_t debounce_window = (uint16_t)(0xffff << (SL_SIMPLE_BUTTON_DEBOUNCE_BITS + 1));
/***************************************************************************//**
* An internal callback called in interrupt context whenever a button changes
* its state. (mode - SL_SIMPLE_BUTTON_MODE_INTERRUPT)
*
* @note The button state is updated by this function. The application callback
* should not update it again.
*
* @param[in] interrupt_no Interrupt number (pin number)
* @param[in] ctx Pointer to button handle
******************************************************************************/
static void sli_simple_button_on_change(uint8_t interrupt_no, void *ctx)
{
(void)interrupt_no;
sl_button_t *button = (sl_button_t *)ctx;
sl_simple_button_context_t *simple_button = button->context;
sl_gpio_t gpio = {
.port = simple_button->port,
.pin = simple_button->pin
};
bool pin_value;
if (simple_button->state != SL_SIMPLE_BUTTON_DISABLED) {
sl_gpio_get_pin_input(&gpio, &pin_value);
simple_button->state = ((bool)pin_value == SL_SIMPLE_BUTTON_POLARITY);
sl_button_on_change(button);
}
}
sl_status_t sl_simple_button_init(const sl_button_t *handle)
{
int32_t interrupt_em4, interrupt_ext;
sl_status_t status;
sl_button_t *button = (sl_button_t *)handle;
sl_simple_button_context_t *simple_button = button->context;
sl_gpio_t gpio = {
.port = simple_button->port,
.pin = simple_button->pin
};
bool pin_value;
sl_clock_manager_enable_bus_clock(SL_BUS_CLOCK_GPIO);
sl_gpio_set_pin_mode(&gpio, SL_SIMPLE_BUTTON_GPIO_MODE, SL_SIMPLE_BUTTON_GPIO_DOUT);
sl_gpio_get_pin_input(&gpio, &pin_value);
simple_button->state = ((bool)pin_value == SL_SIMPLE_BUTTON_POLARITY);
if (simple_button->mode == SL_SIMPLE_BUTTON_MODE_INTERRUPT) {
interrupt_em4 = SL_GPIO_INTERRUPT_UNAVAILABLE;
interrupt_ext = SL_GPIO_INTERRUPT_UNAVAILABLE;
// Try to register an EM4WU interrupt for the given pin
status = sl_gpio_configure_wakeup_em4_interrupt(&gpio,
&interrupt_em4,
SL_SIMPLE_BUTTON_POLARITY,
(sl_gpio_irq_callback_t)sli_simple_button_on_change,
button);
if (interrupt_em4 == SL_GPIO_INTERRUPT_UNAVAILABLE) {
// if the pin not EM4WU-compatible, instead register a regualr interrupt
status = sl_gpio_configure_external_interrupt(&gpio,
&interrupt_ext,
SL_GPIO_INTERRUPT_RISING_FALLING_EDGE,
(sl_gpio_irq_callback_t)sli_simple_button_on_change,
button);
EFM_ASSERT(status == SL_STATUS_OK);
} else {
// If the pin is EM4WU-compatible, setup the pin as an EM4WU pin
// Since EM4WU interrupts are level-sensitive and not edge-sensitive, also register a regular edge-sensitive interrupt to capture the other edge
uint8_t flags;
if (SL_SIMPLE_BUTTON_POLARITY == 0) {
flags = SL_GPIO_INTERRUPT_RISING_EDGE;
} else if (SL_SIMPLE_BUTTON_POLARITY == 1) {
flags = SL_GPIO_INTERRUPT_FALLING_EDGE;
}
status = sl_gpio_configure_external_interrupt(&gpio,
&interrupt_ext,
flags,
(sl_gpio_irq_callback_t)sli_simple_button_on_change,
button);
EFM_ASSERT(status == SL_STATUS_OK);
}
}
return SL_STATUS_OK;
}
sl_button_state_t sl_simple_button_get_state(const sl_button_t *handle)
{
sl_button_t *button = (sl_button_t *)handle;
sl_simple_button_context_t *simple_button = button->context;
return simple_button->state;
}
void sl_simple_button_poll_step(const sl_button_t *handle)
{
sl_button_t *button = (sl_button_t *)handle;
sl_simple_button_context_t *simple_button = button->context;
bool button_press, pin_value;
sl_gpio_t gpio = {
.port = simple_button->port,
.pin = simple_button->pin
};
if (simple_button->state == SL_SIMPLE_BUTTON_DISABLED) {
return;
}
sl_gpio_get_pin_input(&gpio, &pin_value);
button_press = (bool)pin_value;
if (simple_button->mode == SL_SIMPLE_BUTTON_MODE_POLL_AND_DEBOUNCE) {
uint16_t history = simple_button->history;
history = (history << 1) | (button_press ^ SL_SIMPLE_BUTTON_POLARITY) | (debounce_window);
if (history == check_press) {
simple_button->state = SL_SIMPLE_BUTTON_PRESSED;
}
if (history == check_release) {
simple_button->state = SL_SIMPLE_BUTTON_RELEASED;
}
simple_button->history = history;
} else if (simple_button->mode == SL_SIMPLE_BUTTON_MODE_POLL) {
simple_button->state = (button_press == SL_SIMPLE_BUTTON_POLARITY);
}
}
void sl_simple_button_enable(const sl_button_t *handle)
{
sl_button_t *button = (sl_button_t *)handle;
sl_simple_button_context_t *simple_button = button->context;
// Return if the button is not disabled
if (simple_button->state != SL_SIMPLE_BUTTON_DISABLED) {
return;
}
// Clear history
simple_button->history = 0;
// Reinit button
sl_simple_button_init(handle);
}
void sl_simple_button_disable(const sl_button_t *handle)
{
sl_button_t *button = (sl_button_t *)handle;
sl_simple_button_context_t *simple_button = button->context;
// Return if the button is disabled
if (simple_button->state == SL_SIMPLE_BUTTON_DISABLED) {
return;
}
if (simple_button->mode == SL_SIMPLE_BUTTON_MODE_INTERRUPT) {
sl_gpio_deconfigure_external_interrupt(simple_button->pin);
}
// Disable the button
simple_button->state = SL_SIMPLE_BUTTON_DISABLED;
}

View File

@@ -0,0 +1,521 @@
/***************************************************************************//**
* @file
* @brief General Purpose IO (GPIO) driver API
*******************************************************************************
* # License
* <b>Copyright 2024 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* 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.
*
******************************************************************************/
#ifndef SL_GPIO_H
#define SL_GPIO_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdbool.h>
#include "sl_status.h"
#include "sl_device_gpio.h"
#ifndef EM_GPIO_H
#define gpioPortA 0
#define gpioPortB 1
#define gpioPortC 2
#define gpioPortD 3
#define gpioPortE 4
#define gpioPortF 5
#define gpioPortG 6
#define gpioPortH 7
#define gpioPortI 8
#define gpioPortJ 9
#define gpioPortK 10
#endif
/* *INDENT-OFF* */
// *****************************************************************************
/// @addtogroup gpio GPIO - General Purpose Input Output
/// @brief General Purpose Input Output driver
///
/// @li @ref gpio_intro
///
///@n @section gpio_intro Introduction
/// This module contains functions to control the GPIO peripheral of Silicon Labs 32-bit MCUs and SoCs.
/// The GPIO driver is used for external and EM4 interrupt configuration, port and pin configuration.
/// as well as manages the interrupt handler.
///
/// @{
// *****************************************************************************
/* *INDENT-ON* */
/*******************************************************************************
******************************** ENUMS ************************************
******************************************************************************/
/// GPIO Pin directions.
SL_ENUM(sl_gpio_pin_direction_t) {
/// Input direction.
SL_GPIO_PIN_DIRECTION_IN = 0,
/// Output direction.
SL_GPIO_PIN_DIRECTION_OUT
};
/*******************************************************************************
******************************* STRUCTS ***********************************
******************************************************************************/
/***************************************************************************//**
* @brief
* Structure for GPIO port and pin configuration.
******************************************************************************/
typedef struct {
sl_gpio_mode_t mode;
sl_gpio_pin_direction_t direction;
} sl_gpio_pin_config_t;
/*******************************************************************************
******************************* TYPEDEFS **********************************
******************************************************************************/
/***************************************************************************//**
* GPIO interrupt callback function pointer.
*
* @param int_no The pin interrupt number to which the callback function is invoked for.
* @param context Pointer to callback context.
******************************************************************************/
typedef void (*sl_gpio_irq_callback_t)(uint8_t int_no, void *context);
/*******************************************************************************
***************************** PROTOTYPES **********************************
******************************************************************************/
/***************************************************************************//**
* Initialization of GPIO driver module.
*
* @return SL_STATUS_OK if initialization is successful.
******************************************************************************/
sl_status_t sl_gpio_init(void);
/***************************************************************************//**
* Sets the pin direction of GPIO pin.
*
* @param[in] gpio Pointer to GPIO structure with port and pin
* @param[in] pin_dir Pin direction of GPIO pin.
*
* @return SL_STATUS_OK if there's no error.
* SL_STATUS_INVALID_PARAMATER if any of the port, pin, direction parameters are invalid.
* SL_STATUS_INVALID_STATE if GPIO configuration is in lock state.
******************************************************************************/
sl_status_t sl_gpio_set_pin_direction(const sl_gpio_t *gpio,
sl_gpio_pin_direction_t pin_dir);
/***************************************************************************//**
* Set the pin mode and set/clear the pin for GPIO pin.
*
* @param[in] gpio Pointer to GPIO structure with port and pin
* @param[in] mode The desired pin mode.
* @param[in] output_value Value to set/clear for pin output on the port.
* Determines the pull-up/pull-down direction of the pin for
* some input mode configurations.
*
* @return SL_STATUS_OK if there's no error.
* SL_STATUS_INVALID_PARAMETER if any of the port, pin, mode parameters are invalid.
* SL_STATUS_INVALID_STATE if GPIO configuration is in locked state.
******************************************************************************/
sl_status_t sl_gpio_set_pin_mode(const sl_gpio_t *gpio,
sl_gpio_mode_t mode,
bool output_value);
/***************************************************************************//**
* Gets the current configuration selected pin on selected port.
*
* @param[in] gpio Pointer to GPIO structure with port and pin
* @param[out] pin_config Pointer to pin configuration such as mode and direction.
* Pointer acts as an output and returns the configuration of
* selected pin on selected port.
*
* @return SL_STATUS_OK if there's no error.
* SL_STATUS_INVALID_PARAMETER if any of the port, pin parameters are invalid.
* SL_STATUS_NULL_POINTER if pin_config is passed as null.
******************************************************************************/
sl_status_t sl_gpio_get_pin_config(const sl_gpio_t *gpio,
sl_gpio_pin_config_t *pin_config);
/***************************************************************************//**
* Sets the selected pin of the selected port.
*
* @param[in] gpio Pointer to GPIO structure with port and pin
*
* @return SL_STATUS_OK if there's no error.
* SL_STATUS_INVALID_PARAMATER if any of the port, pin parameters are invalid.
******************************************************************************/
sl_status_t sl_gpio_set_pin(const sl_gpio_t *gpio);
/***************************************************************************//**
* Clears the selected pin of the selected port.
*
* @param[in] gpio Pointer to GPIO structure with port and pin
*
* @return SL_STATUS_OK if there's no error.
* SL_STATUS_INVALID_PARAMATER if any of the port, pin parameters are invalid.
******************************************************************************/
sl_status_t sl_gpio_clear_pin(const sl_gpio_t *gpio);
/***************************************************************************//**
* Toggles the state of selected pin on selected port.
*
* @param[in] gpio Pointer to GPIO structure with port and pin
*
* @return SL_STATUS_OK if there's no error.
* SL_STATUS_INVALID_PARAMATER if any of the port, pin parameters are invalid.
******************************************************************************/
sl_status_t sl_gpio_toggle_pin(const sl_gpio_t *gpio);
/***************************************************************************//**
* Gets the output state of selected pin on selected port.
*
* @param[in] gpio Pointer to GPIO structure with port and pin
* @param[out] pin_value Pointer to return output state of selected pin on selected port
* when configured to output mode.
*
* @return SL_STATUS_OK if there's no error.
* SL_STATUS_INVALID_PARAMATER if any of the port, pin parameters are invalid.
* SL_STATUS_NULL_POINTER if pin_value passed as null.
******************************************************************************/
sl_status_t sl_gpio_get_pin_output(const sl_gpio_t *gpio,
bool *pin_value);
/***************************************************************************//**
* Gets the input state of selected pin on selected port.
*
* @param[in] gpio Pointer to GPIO structure with port and pin
* @param[out] pin_value Pointer to return input state of selected pin on selected port
* when configured to input mode.
*
* @return SL_STATUS_OK if there's no error.
* SL_STATUS_INVALID_PARAMATER if any of the port, pin parameters are invalid.
* SL_STATUS_NULL_POINTER if pin_value passed as null.
******************************************************************************/
sl_status_t sl_gpio_get_pin_input(const sl_gpio_t *gpio,
bool *pin_value);
/***************************************************************************//**
* Sets the selected pin(s) of selected port.
*
* @param[in] port The GPIO port to access.
* @param[in] pins Bit mask for pins to set.
*
* @return SL_STATUS_OK if there's no error.
* SL_STATUS_INVALID_PARAMETER if port is invalid.
******************************************************************************/
sl_status_t sl_gpio_set_port(sl_gpio_port_t port,
uint32_t pins);
/***************************************************************************//**
* Clears the selected pin(s) of selected port.
*
* @param[in] port The GPIO Port to access.
* @param[in] pins Bit mask for bits to clear.
*
* @return SL_STATUS_OK if there's no error.
* SL_STATUS_INVALID_PARAMETER if port is invalid.
******************************************************************************/
sl_status_t sl_gpio_clear_port(sl_gpio_port_t port,
uint32_t pins);
/***************************************************************************//**
* Gets the output state of pins of selected port.
*
* @param[in] gpio The GPIO Port to access.
* @param[out] port_value Pointer to return output state of pins on selected port.
*
* @return SL_STATUS_OK if there's no error.
* SL_STATUS_INVALID_PARAMETER if port is invalid.
* SL_STATUS_NULL_POINTER if port_value passed as null.
******************************************************************************/
sl_status_t sl_gpio_get_port_output(sl_gpio_port_t port,
uint32_t *port_value);
/***************************************************************************//**
* Gets the input state of pins of selected port.
*
* @param[in] gpio The GPIO Port to access.
* @param[out] port_value Pointer to return output state of pins on selected port.
*
* @return SL_STATUS_OK if there's no error.
* SL_STATUS_INVALID_PARAMETER if port is invalid.
* SL_STATUS_NULL_POINTER if port_value passed as null.
******************************************************************************/
sl_status_t sl_gpio_get_port_input(sl_gpio_port_t port,
uint32_t *port_value);
/***************************************************************************//**
* Configures the GPIO pin interrupt.
*
* @details By default, this function can be used to register a callback which shall be called upon
* interrupt generated for a given pin interrupt number and enables interrupt.
* This function configures and enables the external interrupt and performs
* callback registration.
* It is recommended to use sl_gpio_deconfigure_external_interrupt()
* to disable the interrupt and unregister the callback.
* see @ref sl_gpio_deconfigure_external_interrupt for more information.
* If a valid interrupt number is provided, operation will proceed accordingly.
* Otherwise, a valid interrupt number will be generated based on provided port and
* pin and used for subsequent operations.
*
* @note If the user has a valid interrupt number to provide as input, it can be used.
* If the user does not have an interrupt number, they can pass -1 (SL_GPIO_INTERRUPT_UNAVAILABLE)
* as value to variable int_no.
* The int_no parameter serves even as an output, a pointer to convey the interrupt number
* for cases where user lacks an interrupt number.
* @note the pin number can be selected freely within a group.
* Interrupt numbers are divided into 4 groups (int_no / 4) and valid pin
* number within the interrupt groups are:
* 0: pins 0-3 (interrupt number 0-3)
* 1: pins 4-7 (interrupt number 4-7)
* 2: pins 8-11 (interrupt number 8-11)
* 3: pins 12-15 (interrupt number 12-15)
*
* @param[in] gpio Pointer to GPIO structure with port and pin
* @param[in/out] int_no Pointer to interrupt number to trigger.
* Pointer that serves as both an input and an output to return int_no
* when the user lacks an int_no.
* @param[in] flags Interrupt flags for interrupt configuration.
* Determines the interrupt to get trigger based on rising/falling edge.
* @param[in] gpio_callback A pointer to gpio callback function.
* @param[in] context A pointer to the callback context.
*
* @return SL_STATUS_OK if there's no error.
* SL_STATUS_INVALID_PARAMETER if any of the port, pin, flag parameters are invalid.
* SL_STATUS_NULL_POINTER if the int_no is passed as NULL.
* SL_STATUS_NOT_FOUND if there's no available interrupt number.
******************************************************************************/
sl_status_t sl_gpio_configure_external_interrupt(const sl_gpio_t *gpio,
int32_t *int_no,
sl_gpio_interrupt_flag_t flags,
sl_gpio_irq_callback_t gpio_callback,
void *context);
/***************************************************************************//**
* Deconfigures the GPIO external pin interrupt.
*
* @details This function can be used to deconfigure the external GPIO interrupt.
* This function performs callback unregistration, clears and disables the
* given interrupt.
*
* @note the pin number can be selected freely within a group.
* Interrupt numbers are divided into 4 groups (int_no / 4) and valid pin
* number within the interrupt groups are:
* 0: pins 0-3 (interrupt number 0-3)
* 1: pins 4-7 (interrupt number 4-7)
* 2: pins 8-11 (interrupt number 8-11)
* 3: pins 12-15 (interrupt number 12-15)
*
* @param[in] int_no Interrupt number to unregister and disable.
*
* @return SL_STATUS_OK if there's no error.
* SL_STATUS_INVALID_PARAMETER if int_no is invalid.
******************************************************************************/
sl_status_t sl_gpio_deconfigure_external_interrupt(int32_t int_no);
/***************************************************************************//**
* Enables one or more GPIO Interrupts.
*
* @param[in] int_mask Mask for GPIO Interrupt sources to enable.
*
* @return SL_STATUS_OK if there's no error.
******************************************************************************/
sl_status_t sl_gpio_enable_interrupts(uint32_t int_mask);
/***************************************************************************//**
* Disables one or more GPIO Interrupts.
*
* @param[in] int_mask Mask for GPIO Interrupt sources to disable.
*
* @return SL_STATUS_OK if there's no error.
******************************************************************************/
sl_status_t sl_gpio_disable_interrupts(uint32_t int_mask);
/***************************************************************************//**
* Configuration EM4WU pins as external level-sensitive interrupts.
*
* @details By default, this function performs callback registration, enables GPIO pin wake-up from EM4,
* sets the wake-up polarity, enables GPIO pin retention and enables the EM4 wake-up interrupt.
* It is recommended to use sl_gpio_deconfigure_wakeup_em4_interrupt()
* to unregister the callback and disable the em4 interrupt as well as GPIO pin wake-up from EM4.
* It is recommended to use sl_gpio_set_pin_em4_retention() to enable/disable the GPIO pin retention.
* see @ref sl_gpio_deconfigure_wakeup_em4_interrupt() and @ref sl_gpio_set_pin_em4_retention().
* If a valid EM4 wake-up interrupt number is provided, operation will proceed accordingly.
* Otherwise, a valid EM4 interrupt number will be generated based on provided EM4 configured
* port and pin and used for subsequent operations.
*
* @note If the user has a valid em4 interrupt number to provide as input, it can be used.
* If the user does not have an interrupt number, they can pass -1 (SL_GPIO_INTERRUPT_UNAVAILABLE)
* as value to variable em4_int_no.
* The em4_int_no parameter serves even as an output, a pointer to convey the em4 interrupt number
* for cases where user lacks an em4 interrupt number.
* @note There are specific ports and pins mapped to an existent EM4WU interrupt
* Each EM4WU signal is connected to a fixed pin and port.
* Based on chip, EM4 wake up interrupts configured port and pin might vary.
*
* @param[in] gpio Pointer to GPIO structure with port and pin
* @param[in/out] em4_int_no Pointer to interrupt number to trigger.
* Pointer that serves as both an input and an output to return em4_int_no
* when the user lacks an em4_int_no.
* @param[in] polarity Determines the wakeup polarity.
* true = Active high level-sensitive interrupt.
* false = Active low level-sensitive interrupt.
* @param[in] gpio_callback A pointer to callback.
* @param[in] context A pointer to callback context.
*
* @return SL_STATUS_OK if there's no error.
* SL_STATUS_INVALID_PARAMETER if any of the port, pin parameters are invalid.
* SL_STATUS_NULL_POINTER if the int_no is passed as NULL.
* SL_STATUS_NOT_FOUND if there's no available interrupt number.
******************************************************************************/
sl_status_t sl_gpio_configure_wakeup_em4_interrupt(const sl_gpio_t *gpio,
int32_t *em4_int_no,
bool polarity,
sl_gpio_irq_callback_t gpio_callback,
void *context);
/***************************************************************************//**
* Utilize this function to deconfigure the EM4 GPIO pin interrupt.
* It serves to unregister a callback, disable/clear interrupt and clear em4 wakeup source.
*
* @details This function performs callback unregistration, clears and disables given em4
* interrupt and disables GPIO pin wake-up from EM4.
*
* @param[in] em4_int_no EM4 wakeup interrupt number.
*
* @return SL_STATUS_OK if there's no error.
* SL_STATUS_INVALID_PARAMETER if em4_int_no is invalid.
******************************************************************************/
sl_status_t sl_gpio_deconfigure_wakeup_em4_interrupt(int32_t em4_int_no);
/***************************************************************************//**
* Enable EM4 GPIO pin Wake-up bit.
* Sets the wakeup and polarity of the EM4 wakeup.
*
* @param[in] em4_int_mask Mask for setting desired EM4 wake up interrupt to enable.
* Mask contains the bitwise logic OR of which EM4 wake up interrupt to
* enable.
* @param[in] em4_polarity_mask Mask for setting the wake up polarity for the EM4 wake up interrupt.
* Mask contains the bitwise logic OR of EM4 wake-up interrupt polarity.
*
* @return SL_STATUS_OK if there's no error.
******************************************************************************/
sl_status_t sl_gpio_enable_pin_em4_wakeup(uint32_t em4_int_mask,
uint32_t em4_polarity_mask);
/***************************************************************************//**
* Disabled the GPIO wake up from EM4.
*
* @param[in] pinmask Mask for clearing desired EM4 wake up interrupt to disable.
* Mask contains the bitwise logic OR of which EM4 wake up interrupt to
* disable.
*
* @return SL_STATUS_OK if there's no error.
******************************************************************************/
sl_status_t sl_gpio_disable_pin_em4_wakeup(uint32_t em4_int_mask);
/***************************************************************************//**
* Enable/Disable GPIO pin retention of output enable, output value, pull enable, and pull direction in EM4.
*
* @param[in] enable true - enables EM4 pin retention.
* false - disables EM4 pin retention.
*
* @return SL_STATUS_OK if there's no error.
******************************************************************************/
sl_status_t sl_gpio_set_pin_em4_retention(bool enable);
/***************************************************************************//**
* Sets slewrate for selected port.
*
* @param[in] port The GPIO port to configure.
* @param[in] slewrate The slewrate to configure the GPIO port.
*
* @return SL_STATUS_OK if there's no error.
* SL_STATUS_INVALID_PARAMETER if port is invalid.
******************************************************************************/
sl_status_t sl_gpio_set_slew_rate(sl_gpio_port_t port,
uint8_t slewrate);
/***************************************************************************//**
* Gets slewrate for selected port.
*
* @param[in] port The GPIO port to get slewrate.
* @param[out] slewrate Pointer to store the slewrate of selected port.
*
* @return SL_STATUS_OK if there's no error.
* SL_STATUS_INVALID_PARAMETER if port is invalid.
* SL_STATUS_NULL_POINTER if slewrate is passed as null.
******************************************************************************/
sl_status_t sl_gpio_get_slew_rate(sl_gpio_port_t port,
uint8_t *slewrate);
/***************************************************************************//**
* Locks the GPIO Configuration.
*
* @note This API locks the functionalities such as sl_gpio_set_pin_mode(),
* sl_gpio_configure_external_interrupt() and sl_gpio_configure_wakeup_em4_interrupt().
* After locking the GPIO configuration, use sl_gpio_unlock API to unlock
* the GPIO configuration to use mentioned functionalities.
*
* @return SL_STATUS_OK if there's no error.
******************************************************************************/
sl_status_t sl_gpio_lock(void);
/***************************************************************************//**
* Unlocks the GPIO Configuration.
*
* @note After locking the GPIO configuration it is recommended to unlock the GPIO configuration
* using sl_gpio_unlock(). You can determine if the GPIO configuration is locked or unlocked
* by using the sl_gpio_is_locked() function.
* Before using certain functions like sl_gpio_set_pin_mode(),
* sl_gpio_configure_external_interrupt(), and sl_gpio_configure_wakeup_em4_interrupt(),
* it's important to check if the GPIO configuration lock is unlocked.
*
* @return SL_STATUS_OK if there's no error.
******************************************************************************/
sl_status_t sl_gpio_unlock(void);
/***************************************************************************//**
* Gets current GPIO Lock status.
*
* @note This function helps check the current status of GPIO configuration.
*
* @param[out] state Pointer to current state of GPIO configuration (lock/unlock).
*
* @return SL_STATUS_OK if there's no error.
* SL_STATUS_NULL_POINTER if state is passed as null.
******************************************************************************/
sl_status_t sl_gpio_is_locked(bool *state);
/** @} (end addtogroup gpio driver) */
#ifdef __cplusplus
}
#endif
#endif /* SL_GPIO_H */

View File

@@ -0,0 +1,824 @@
/***************************************************************************//**
* @file
* @brief General Purpose IO (GPIO) driver API
*******************************************************************************
* # License
* <b>Copyright 2024 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* 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 <stddef.h>
#include "sl_core.h"
#include "sl_common.h"
#include "sl_interrupt_manager.h"
#include "sl_clock_manager.h"
#include "sl_hal_gpio.h"
#include "sl_gpio.h"
/*******************************************************************************
******************************* DEFINES ***********************************
******************************************************************************/
/// Define for supporting gpiointerrupt porting
#define SL_GPIO_PORT_INTERRUPT (0xFF)
/// Pin direction validation.
#define SL_GPIO_DIRECTION_IS_VALID(direction) (direction <= SL_GPIO_PIN_DIRECTION_OUT)
/*******************************************************************************
******************************* STRUCTS ***********************************
******************************************************************************/
typedef struct {
// Pin interrupt number in range 0 to 15.
uint32_t int_no;
// Pointer to callback function.
void *callback;
// Pointer to callback context.
void *context;
} sl_gpio_callback_desc_t;
typedef struct {
// An array of user callbacks for external interrupts.
// We have external interrupts configured from 0 to 15 bits.
sl_gpio_callback_desc_t callback_ext[SL_HAL_GPIO_INTERRUPT_MAX];
// An array of user callbacks for EM4 interrupts.
// We have EM4 interrupts configured from 16 to 31 bits.
sl_gpio_callback_desc_t callback_em4[SL_HAL_GPIO_INTERRUPT_MAX];
} sl_gpio_callbacks_t;
/*******************************************************************************
******************************** GLOBALS **********************************
******************************************************************************/
// Variable to manage and organize the callback functions for External and EM4 interrupts.
static sl_gpio_callbacks_t gpio_interrupts = { 0 };
/*******************************************************************************
****************************** LOCAL FUCTIONS *****************************
******************************************************************************/
static void sl_gpio_dispatch_interrupt(uint32_t iflags);
/***************************************************************************//**
* Driver GPIO Initialization.
******************************************************************************/
sl_status_t sl_gpio_init()
{
sl_clock_manager_enable_bus_clock(SL_BUS_CLOCK_GPIO);
if (sl_interrupt_manager_is_irq_disabled(GPIO_ODD_IRQn)) {
sl_interrupt_manager_clear_irq_pending(GPIO_ODD_IRQn);
sl_interrupt_manager_enable_irq(GPIO_ODD_IRQn);
}
if (sl_interrupt_manager_is_irq_disabled(GPIO_EVEN_IRQn)) {
sl_interrupt_manager_clear_irq_pending(GPIO_EVEN_IRQn);
sl_interrupt_manager_enable_irq(GPIO_EVEN_IRQn);
}
return SL_STATUS_OK;
}
/***************************************************************************//**
* Sets the pin direction for GPIO pin.
******************************************************************************/
sl_status_t sl_gpio_set_pin_direction(const sl_gpio_t *gpio,
sl_gpio_pin_direction_t pin_direction)
{
CORE_DECLARE_IRQ_STATE;
if (gpio == NULL) {
EFM_ASSERT(false);
return SL_STATUS_NULL_POINTER;
}
if (!SL_HAL_GPIO_PORT_PIN_IS_VALID(gpio->port, gpio->pin) || !SL_GPIO_DIRECTION_IS_VALID(pin_direction)) {
EFM_ASSERT(false);
return SL_STATUS_INVALID_PARAMETER;
}
if (sl_hal_gpio_get_lock_status() != 0) {
EFM_ASSERT(false);
return SL_STATUS_INVALID_STATE;
}
CORE_ENTER_ATOMIC();
if (pin_direction == SL_GPIO_PIN_DIRECTION_OUT) {
sl_hal_gpio_set_pin_mode(gpio, SL_GPIO_MODE_PUSH_PULL, 1);
} else if (pin_direction == SL_GPIO_PIN_DIRECTION_IN) {
sl_hal_gpio_set_pin_mode(gpio, SL_GPIO_MODE_INPUT, 0);
}
CORE_EXIT_ATOMIC();
return SL_STATUS_OK;
}
/***************************************************************************//**
* Sets the mode for GPIO pin and pin direction.
******************************************************************************/
sl_status_t sl_gpio_set_pin_mode(const sl_gpio_t *gpio,
sl_gpio_mode_t mode,
bool output_value)
{
CORE_DECLARE_IRQ_STATE;
if (gpio == NULL) {
EFM_ASSERT(false);
return SL_STATUS_NULL_POINTER;
}
if (!SL_HAL_GPIO_MODE_IS_VALID(mode) || !SL_HAL_GPIO_PORT_PIN_IS_VALID(gpio->port, gpio->pin)) {
EFM_ASSERT(false);
return SL_STATUS_INVALID_PARAMETER;
}
if (sl_hal_gpio_get_lock_status() != 0) {
EFM_ASSERT(false);
return SL_STATUS_INVALID_STATE;
}
CORE_ENTER_ATOMIC();
sl_hal_gpio_set_pin_mode(gpio, mode, output_value);
CORE_EXIT_ATOMIC();
return SL_STATUS_OK;
}
/***************************************************************************//**
* Gets the current configuration selected pin on selected port.
******************************************************************************/
sl_status_t sl_gpio_get_pin_config(const sl_gpio_t *gpio,
sl_gpio_pin_config_t *pin_config)
{
CORE_DECLARE_IRQ_STATE;
if (gpio == NULL || pin_config == NULL) {
EFM_ASSERT(false);
return SL_STATUS_NULL_POINTER;
}
if (!SL_HAL_GPIO_PORT_PIN_IS_VALID(gpio->port, gpio->pin)) {
EFM_ASSERT(false);
return SL_STATUS_INVALID_PARAMETER;
}
CORE_ENTER_ATOMIC();
pin_config->mode = sl_hal_gpio_get_pin_mode(gpio);
switch (pin_config->mode) {
case SL_GPIO_MODE_INPUT:
case SL_GPIO_MODE_INPUT_PULL:
case SL_GPIO_MODE_INPUT_PULL_FILTER:
pin_config->direction = SL_GPIO_PIN_DIRECTION_IN;
break;
case SL_GPIO_MODE_DISABLED:
case SL_GPIO_MODE_PUSH_PULL:
case SL_GPIO_MODE_PUSH_PULL_ALTERNATE:
case SL_GPIO_MODE_WIRED_OR:
case SL_GPIO_MODE_WIRED_OR_PULL_DOWN:
case SL_GPIO_MODE_WIRED_AND:
case SL_GPIO_MODE_WIRED_AND_FILTER:
case SL_GPIO_MODE_WIRED_AND_PULLUP:
case SL_GPIO_MODE_WIRED_AND_PULLUP_FILTER:
case SL_GPIO_MODE_WIRED_AND_ALTERNATE:
case SL_GPIO_MODE_WIRED_AND_ALTERNATE_FILTER:
case SL_GPIO_MODE_WIRED_AND_ALTERNATE_PULLUP:
case SL_GPIO_MODE_WIRED_AND_ALTERNATE_PULLUP_FILTER:
pin_config->direction = SL_GPIO_PIN_DIRECTION_OUT;
break;
default:
CORE_EXIT_ATOMIC();
EFM_ASSERT(false);
return SL_STATUS_INVALID_MODE;
}
CORE_EXIT_ATOMIC();
return SL_STATUS_OK;
}
/***************************************************************************//**
* Sets the DOUT of selected pin on selected port.
******************************************************************************/
sl_status_t sl_gpio_set_pin(const sl_gpio_t *gpio)
{
CORE_DECLARE_IRQ_STATE;
if (gpio == NULL) {
EFM_ASSERT(false);
return SL_STATUS_NULL_POINTER;
}
if (!SL_HAL_GPIO_PORT_PIN_IS_VALID(gpio->port, gpio->pin)) {
EFM_ASSERT(false);
return SL_STATUS_INVALID_PARAMETER;
}
CORE_ENTER_ATOMIC();
sl_hal_gpio_set_pin(gpio);
CORE_EXIT_ATOMIC();
return SL_STATUS_OK;
}
/***************************************************************************//**
* Clears the DOUT of selected pin on selected port.
******************************************************************************/
sl_status_t sl_gpio_clear_pin(const sl_gpio_t *gpio)
{
CORE_DECLARE_IRQ_STATE;
if (gpio == NULL) {
EFM_ASSERT(false);
return SL_STATUS_NULL_POINTER;
}
if (!SL_HAL_GPIO_PORT_PIN_IS_VALID(gpio->port, gpio->pin)) {
EFM_ASSERT(false);
return SL_STATUS_INVALID_PARAMETER;
}
CORE_ENTER_ATOMIC();
sl_hal_gpio_clear_pin(gpio);
CORE_EXIT_ATOMIC();
return SL_STATUS_OK;
}
/***************************************************************************//**
* Toggles the DOUT of selected pin on selected port.
******************************************************************************/
sl_status_t sl_gpio_toggle_pin(const sl_gpio_t *gpio)
{
CORE_DECLARE_IRQ_STATE;
if (gpio == NULL) {
EFM_ASSERT(false);
return SL_STATUS_NULL_POINTER;
}
if (!SL_HAL_GPIO_PORT_PIN_IS_VALID(gpio->port, gpio->pin)) {
EFM_ASSERT(false);
return SL_STATUS_INVALID_PARAMETER;
}
CORE_ENTER_ATOMIC();
sl_hal_gpio_toggle_pin(gpio);
CORE_EXIT_ATOMIC();
return SL_STATUS_OK;
}
/***************************************************************************//**
* Gets the output state of selected pin on selected port.
******************************************************************************/
sl_status_t sl_gpio_get_pin_output(const sl_gpio_t *gpio,
bool *pin_value)
{
CORE_DECLARE_IRQ_STATE;
if (gpio == NULL || pin_value == NULL) {
EFM_ASSERT(false);
return SL_STATUS_NULL_POINTER;
}
if (!SL_HAL_GPIO_PORT_PIN_IS_VALID(gpio->port, gpio->pin)) {
EFM_ASSERT(false);
return SL_STATUS_INVALID_PARAMETER;
}
CORE_ENTER_ATOMIC();
*pin_value = sl_hal_gpio_get_pin_output(gpio);
CORE_EXIT_ATOMIC();
return SL_STATUS_OK;
}
/***************************************************************************//**
* Gets the input state of selected pin on selected port.
******************************************************************************/
sl_status_t sl_gpio_get_pin_input(const sl_gpio_t *gpio,
bool *pin_value)
{
CORE_DECLARE_IRQ_STATE;
if (gpio == NULL || pin_value == NULL) {
EFM_ASSERT(false);
return SL_STATUS_NULL_POINTER;
}
if (!SL_HAL_GPIO_PORT_PIN_IS_VALID(gpio->port, gpio->pin)) {
EFM_ASSERT(false);
return SL_STATUS_INVALID_PARAMETER;
}
CORE_ENTER_ATOMIC();
*pin_value = sl_hal_gpio_get_pin_input(gpio);
CORE_EXIT_ATOMIC();
return SL_STATUS_OK;
}
/***************************************************************************//**
* Sets the selected pin(s) on selected port.
******************************************************************************/
sl_status_t sl_gpio_set_port(sl_gpio_port_t port,
uint32_t pins)
{
CORE_DECLARE_IRQ_STATE;
if (!SL_HAL_GPIO_PORT_IS_VALID(port)) {
EFM_ASSERT(false);
return SL_STATUS_INVALID_PARAMETER;
}
CORE_ENTER_ATOMIC();
sl_hal_gpio_set_port(port, pins);
CORE_EXIT_ATOMIC();
return SL_STATUS_OK;
}
/***************************************************************************//**
* Clears the selected pin on selected port.
******************************************************************************/
sl_status_t sl_gpio_clear_port(sl_gpio_port_t port,
uint32_t pins)
{
CORE_DECLARE_IRQ_STATE;
if (!SL_HAL_GPIO_PORT_IS_VALID(port)) {
EFM_ASSERT(false);
return SL_STATUS_INVALID_PARAMETER;
}
CORE_ENTER_ATOMIC();
sl_hal_gpio_clear_port(port, pins);
CORE_EXIT_ATOMIC();
return SL_STATUS_OK;
}
/***************************************************************************//**
* Gets the output state of pins of selected port.
******************************************************************************/
sl_status_t sl_gpio_get_port_output(sl_gpio_port_t port,
uint32_t *port_value)
{
CORE_DECLARE_IRQ_STATE;
if (!SL_HAL_GPIO_PORT_IS_VALID(port)) {
EFM_ASSERT(false);
return SL_STATUS_INVALID_PARAMETER;
}
if (port_value == NULL) {
EFM_ASSERT(false);
return SL_STATUS_NULL_POINTER;
}
CORE_ENTER_ATOMIC();
*port_value = sl_hal_gpio_get_port_output(port);
CORE_EXIT_ATOMIC();
return SL_STATUS_OK;
}
/***************************************************************************//**
* Gets the input state of pins of selected port.
******************************************************************************/
sl_status_t sl_gpio_get_port_input(sl_gpio_port_t port,
uint32_t *port_value)
{
CORE_DECLARE_IRQ_STATE;
if (!SL_HAL_GPIO_PORT_IS_VALID(port)) {
EFM_ASSERT(false);
return SL_STATUS_INVALID_PARAMETER;
}
if (port_value == NULL) {
EFM_ASSERT(false);
return SL_STATUS_NULL_POINTER;
}
CORE_ENTER_ATOMIC();
*port_value = sl_hal_gpio_get_port_input(port);
CORE_EXIT_ATOMIC();
return SL_STATUS_OK;
}
/***************************************************************************//**
* Configuring the GPIO external pin interrupt.
* This API can be used to configure interrupt and to register the callback.
******************************************************************************/
sl_status_t sl_gpio_configure_external_interrupt(const sl_gpio_t *gpio,
int32_t *int_no,
sl_gpio_interrupt_flag_t flags,
sl_gpio_irq_callback_t gpio_callback,
void *context)
{
uint32_t enabled_interrupts;
CORE_DECLARE_IRQ_STATE;
if (gpio == NULL || int_no == NULL) {
EFM_ASSERT(false);
return SL_STATUS_NULL_POINTER;
}
if (!SL_HAL_GPIO_PORT_PIN_IS_VALID(gpio->port, gpio->pin) && (gpio->port != SL_GPIO_PORT_INTERRUPT)) {
EFM_ASSERT(false);
return SL_STATUS_INVALID_PARAMETER;
}
if (!SL_GPIO_FLAG_IS_VALID(flags)) {
EFM_ASSERT(false);
return SL_STATUS_INVALID_PARAMETER;
}
CORE_ENTER_ATOMIC();
if (gpio->port != SL_GPIO_PORT_INTERRUPT) {
*int_no = sl_hal_gpio_configure_external_interrupt(gpio, *int_no, flags);
}
if (*int_no == SL_GPIO_INTERRUPT_UNAVAILABLE && gpio->port == SL_GPIO_PORT_INTERRUPT) {
enabled_interrupts = sl_hal_gpio_get_enabled_interrupts();
*int_no = sl_hal_gpio_get_external_interrupt_number(gpio->pin, enabled_interrupts);
}
if (*int_no != SL_GPIO_INTERRUPT_UNAVAILABLE) {
// Callback registration.
gpio_interrupts.callback_ext[*int_no].callback = (void *)gpio_callback;
gpio_interrupts.callback_ext[*int_no].context = context;
if (gpio->port != SL_GPIO_PORT_INTERRUPT) {
sl_hal_gpio_enable_interrupts(1 << *int_no);
}
} else {
CORE_EXIT_ATOMIC();
return SL_STATUS_NOT_FOUND;
}
CORE_EXIT_ATOMIC();
return SL_STATUS_OK;
}
/***************************************************************************//**
* Deconfigures the GPIO external pin interrupt.
* This API can be used to deconfigure the interrupt and to unregister the callback.
******************************************************************************/
sl_status_t sl_gpio_deconfigure_external_interrupt(int32_t int_no)
{
CORE_DECLARE_IRQ_STATE;
if (!((int_no != SL_GPIO_INTERRUPT_UNAVAILABLE) && (int_no <= SL_HAL_GPIO_INTERRUPT_MAX) && (int_no >= 0))) {
EFM_ASSERT(false);
return SL_STATUS_INVALID_PARAMETER;
}
CORE_ENTER_ATOMIC();
// Clear pending interrupt.
sl_hal_gpio_clear_interrupts(1 << int_no);
sl_hal_gpio_disable_interrupts(1 << int_no);
// Callback deregistration.
gpio_interrupts.callback_ext[int_no].callback = NULL;
gpio_interrupts.callback_ext[int_no].context = NULL;
CORE_EXIT_ATOMIC();
return SL_STATUS_OK;
}
/***************************************************************************//**
* Enables one or more GPIO interrupts.
******************************************************************************/
sl_status_t sl_gpio_enable_interrupts(uint32_t flags)
{
CORE_DECLARE_IRQ_STATE;
CORE_ENTER_ATOMIC();
sl_hal_gpio_enable_interrupts(flags);
CORE_EXIT_ATOMIC();
return SL_STATUS_OK;
}
/***************************************************************************//**
* Disables one or more GPIO interrupts.
******************************************************************************/
sl_status_t sl_gpio_disable_interrupts(uint32_t flags)
{
CORE_DECLARE_IRQ_STATE;
CORE_ENTER_ATOMIC();
sl_hal_gpio_disable_interrupts(flags);
CORE_EXIT_ATOMIC();
return SL_STATUS_OK;
}
/***************************************************************************//**
* Configures the EM4WU pin as external level interrupts for waking up from EM mode.
* Registering/unregistering the callbacks and Configuring the EM4 interrupts to enable/disable
******************************************************************************/
sl_status_t sl_gpio_configure_wakeup_em4_interrupt(const sl_gpio_t *gpio,
int32_t *em4_int_no,
bool polarity,
sl_gpio_irq_callback_t gpio_callback,
void *context)
{
CORE_DECLARE_IRQ_STATE;
if (gpio == NULL || em4_int_no == NULL) {
EFM_ASSERT(false);
return SL_STATUS_NULL_POINTER;
}
if (!SL_HAL_GPIO_PORT_PIN_IS_VALID(gpio->port, gpio->pin) && (gpio->port != SL_GPIO_PORT_INTERRUPT)) {
EFM_ASSERT(false);
return SL_STATUS_INVALID_PARAMETER;
}
CORE_ENTER_ATOMIC();
if (gpio->port != SL_GPIO_PORT_INTERRUPT) {
*em4_int_no = sl_hal_gpio_configure_wakeup_em4_external_interrupt(gpio, *em4_int_no, polarity);
}
if (*em4_int_no != SL_GPIO_INTERRUPT_UNAVAILABLE) {
// Callback registration.
gpio_interrupts.callback_em4[*em4_int_no].callback = (void *)gpio_callback;
gpio_interrupts.callback_em4[*em4_int_no].context = context;
if (gpio->port != SL_GPIO_PORT_INTERRUPT) {
sl_hal_gpio_enable_interrupts(1 << (*em4_int_no + SL_HAL_GPIO_EM4WUEN_SHIFT));
}
} else {
CORE_EXIT_ATOMIC();
return SL_STATUS_NOT_FOUND;
}
CORE_EXIT_ATOMIC();
return SL_STATUS_OK;
}
/***************************************************************************//**
* Deconfigures the EM4 GPIO pin interrupt.
* Unregisters a callback, disable/clear interrupt and clear em4 wakeup source
******************************************************************************/
sl_status_t sl_gpio_deconfigure_wakeup_em4_interrupt(int32_t em4_int_no)
{
CORE_DECLARE_IRQ_STATE;
if (!((em4_int_no != SL_GPIO_INTERRUPT_UNAVAILABLE) && (em4_int_no <= SL_HAL_GPIO_INTERRUPT_MAX) && (em4_int_no >= 0))) {
EFM_ASSERT(false);
return SL_STATUS_INVALID_PARAMETER;
}
CORE_ENTER_ATOMIC();
// Clear any pending interrupt.
sl_hal_gpio_clear_interrupts(1 << (em4_int_no + SL_HAL_GPIO_EM4WUEN_SHIFT));
sl_hal_gpio_disable_pin_em4_wakeup(1 << (em4_int_no + SL_HAL_GPIO_EM4WUEN_SHIFT));
sl_hal_gpio_disable_interrupts(1 << (em4_int_no + SL_HAL_GPIO_EM4WUEN_SHIFT));
/* Callback deregistration */
gpio_interrupts.callback_em4[em4_int_no].callback = NULL;
gpio_interrupts.callback_em4[em4_int_no].context = NULL;
CORE_EXIT_ATOMIC();
return SL_STATUS_OK;
}
/***************************************************************************//**
* Sets GPIO EM4 Wake up interrupt to Enable and EM4 Wake up interrupt polarity
******************************************************************************/
sl_status_t sl_gpio_enable_pin_em4_wakeup(uint32_t em4_int_mask,
uint32_t em4_polarity_mask)
{
uint32_t int_mask = 0;
uint32_t polarity_mask = 0;
CORE_DECLARE_IRQ_STATE;
CORE_ENTER_ATOMIC();
// Enable EM4WU function and set polarity.
int_mask |= (em4_int_mask << _GPIO_EM4WUEN_EM4WUEN_SHIFT);
polarity_mask |= (em4_polarity_mask << _GPIO_EM4WUEN_EM4WUEN_SHIFT);
sl_hal_gpio_enable_pin_em4_wakeup(int_mask, polarity_mask);
CORE_EXIT_ATOMIC();
return SL_STATUS_OK;
}
/***************************************************************************//**
* Clears GPIO EM4 Wake up enable
******************************************************************************/
sl_status_t sl_gpio_disable_pin_em4_wakeup(uint32_t em4_int_mask)
{
uint32_t int_mask = 0;
CORE_DECLARE_IRQ_STATE;
CORE_ENTER_ATOMIC();
// Disable EM4WU function.
int_mask |= (em4_int_mask << _GPIO_EM4WUEN_EM4WUEN_SHIFT);
sl_hal_gpio_disable_pin_em4_wakeup(int_mask);
CORE_EXIT_ATOMIC();
return SL_STATUS_OK;
}
/***************************************************************************//**
* Enable GPIO pin retention of output enable, output value, pull direction, pull enable in EM4
******************************************************************************/
sl_status_t sl_gpio_set_pin_em4_retention(bool enable)
{
CORE_DECLARE_IRQ_STATE;
CORE_ENTER_ATOMIC();
sl_hal_gpio_set_pin_em4_retention(enable);
CORE_EXIT_ATOMIC();
return SL_STATUS_OK;
}
/***************************************************************************//**
* Sets slewrate for selected port.
******************************************************************************/
sl_status_t sl_gpio_set_slew_rate(sl_gpio_port_t port,
uint8_t slewrate)
{
CORE_DECLARE_IRQ_STATE;
if (!SL_HAL_GPIO_PORT_IS_VALID(port)) {
EFM_ASSERT(false);
return SL_STATUS_INVALID_PARAMETER;
}
CORE_ENTER_ATOMIC();
sl_hal_gpio_set_slew_rate(port, slewrate);
CORE_EXIT_ATOMIC();
return SL_STATUS_OK;
}
/***************************************************************************//**
* Gets slewrate for selected port.
******************************************************************************/
sl_status_t sl_gpio_get_slew_rate(sl_gpio_port_t port,
uint8_t *slewrate)
{
CORE_DECLARE_IRQ_STATE;
if (!SL_HAL_GPIO_PORT_IS_VALID(port)) {
EFM_ASSERT(false);
return SL_STATUS_INVALID_PARAMETER;
}
if (slewrate == NULL) {
EFM_ASSERT(false);
return SL_STATUS_NULL_POINTER;
}
CORE_ENTER_ATOMIC();
*slewrate = sl_hal_gpio_get_slew_rate(port);
CORE_EXIT_ATOMIC();
return SL_STATUS_OK;
}
/***************************************************************************//**
* Locks the GPIO Configuration
******************************************************************************/
sl_status_t sl_gpio_lock(void)
{
sl_hal_gpio_lock();
return SL_STATUS_OK;
}
/***************************************************************************//**
* Unlocks the GPIO Configuration
******************************************************************************/
sl_status_t sl_gpio_unlock(void)
{
sl_hal_gpio_unlock();
return SL_STATUS_OK;
}
/***************************************************************************//**
* Gets the GPIO State
******************************************************************************/
sl_status_t sl_gpio_is_locked(bool *state)
{
uint32_t status;
CORE_DECLARE_IRQ_STATE;
if (state == NULL) {
EFM_ASSERT(false);
return SL_STATUS_NULL_POINTER;
}
CORE_ENTER_ATOMIC();
status = sl_hal_gpio_get_lock_status();
if (status) {
// true - GPIO configuration registers are locked.
*state = true;
} else {
// false - GPIO configuration registers are unlocked.
*state = false;
}
CORE_EXIT_ATOMIC();
return SL_STATUS_OK;
}
/***************************************************************************//**
* Function calls users callback for registered pin interrupts.
*
* @details This function is called when GPIO interrupts are handled by the IRQHandlers.
* Function gets even or odd interrupt flags and calls user callback
* registered for that pin. Function iterates on flags starting from MSB.
*
* @param iflags Interrupt flags which shall be handled by the dispatcher.
******************************************************************************/
static void sl_gpio_dispatch_interrupt(uint32_t iflags)
{
uint32_t irq_idx;
sl_gpio_callback_desc_t *callback;
sl_gpio_irq_callback_t func;
// Check for flags set in IF register.
while (iflags != 0) {
irq_idx = SL_CTZ(iflags);
iflags &= ~(1UL << irq_idx);
if (irq_idx <= SL_HAL_GPIO_INTERRUPT_MAX) {
callback = &gpio_interrupts.callback_ext[irq_idx];
} else {
callback = &gpio_interrupts.callback_em4[irq_idx - SL_HAL_GPIO_EM4WUEN_SHIFT];
irq_idx = irq_idx - SL_HAL_GPIO_EM4WUEN_SHIFT;
}
// Call user callback.
if (callback->callback) {
func = (sl_gpio_irq_callback_t)(callback->callback);
func((uint8_t)irq_idx, callback->context);
}
}
}
/***************************************************************************//**
* GPIO EVEN interrupt handler. Interrupt handler clears all IF even flags and
* call the dispatcher passing the flags which triggered the interrupt.
******************************************************************************/
void GPIO_EVEN_IRQHandler(void)
{
uint32_t even_flags;
// Gets all enabled and pending even interrupts.
even_flags = sl_hal_gpio_get_enabled_pending_interrupts() & SL_HAL_GPIO_INT_IF_EVEN_MASK;
// Clears only even interrupts.
sl_hal_gpio_clear_interrupts(even_flags);
sl_gpio_dispatch_interrupt(even_flags);
}
/***************************************************************************//**
* @brief
* GPIO ODD interrupt handler. Interrupt handler clears all IF odd flags and
* call the dispatcher passing the flags which triggered the interrupt.
******************************************************************************/
void GPIO_ODD_IRQHandler(void)
{
uint32_t odd_flags;
// Gets all enabled and pending odd interrupts.
odd_flags = sl_hal_gpio_get_enabled_pending_interrupts() & SL_HAL_GPIO_INT_IF_ODD_MASK;
// Clears only odd interrupts.
sl_hal_gpio_clear_interrupts(odd_flags);
sl_gpio_dispatch_interrupt(odd_flags);
}

View File

@@ -0,0 +1,183 @@
/***************************************************************************//**
* @file
* @brief LED Driver
*******************************************************************************
* # License
* <b>Copyright 2019 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* 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.
*
******************************************************************************/
#ifndef SL_LED_H
#define SL_LED_H
#include <stdint.h>
#include "sl_status.h"
#ifdef __cplusplus
extern "C" {
#endif
/***************************************************************************//**
* @addtogroup led LED Driver
* @brief Generic LED Driver
* @{
******************************************************************************/
/*******************************************************************************
****************************** DEFINES ************************************
******************************************************************************/
#define SL_LED_CURRENT_STATE_OFF 0U ///< LED state off
#define SL_LED_CURRENT_STATE_ON 1U ///< LED state on
/*******************************************************************************
***************************** DATA TYPES **********************************
******************************************************************************/
typedef uint8_t sl_led_state_t; ///< LED state
/// A LED instance
typedef struct {
void *context; ///< The context for this LED instance
sl_status_t (*init)(void *context); ///< Member function to initialize LED instance
void (*turn_on)(void *context); ///< Member function to turn on LED
void (*turn_off)(void *context); ///< Member function to turn off LED
void (*toggle)(void *context); ///< Member function to toggle LED
sl_led_state_t (*get_state)(void *context); ///< Member function to retrieve LED state
} sl_led_t;
/*******************************************************************************
***************************** PROTOTYPES **********************************
******************************************************************************/
/***************************************************************************//**
* Initialize the LED driver. Call this function before any other LED
* function. Initializes the selected LED GPIO, mode, and polarity.
*
* @param[in] led_handle Pointer to instance of sl_led_t to initialize
*
* @return Status Code:
* - SL_STATUS_OK
******************************************************************************/
sl_status_t sl_led_init(const sl_led_t *led_handle);
/***************************************************************************//**
* Turn on the LED.
*
* @param[in] led_handle Pointer to instance of sl_led_t to turn on
******************************************************************************/
void sl_led_turn_on(const sl_led_t *led_handle);
/***************************************************************************//**
* Turn off the LED.
*
* @param[in] led_handle Pointer to instance of sl_led_t to turn off
******************************************************************************/
void sl_led_turn_off(const sl_led_t *led_handle);
/***************************************************************************//**
* Toggle the LED. Turn it on if it is off, and off if it is on.
*
* @param[in] led_handle Pointer to instance of sl_led_t to toggle
******************************************************************************/
void sl_led_toggle(const sl_led_t *led_handle);
/***************************************************************************//**
* Get the current state of the LED.
*
* @param[in] led_handle Pointer to instance of sl_led_t to check
*
* @return sl_led_state_t Current state of LED. 1 for on, 0 for off
******************************************************************************/
sl_led_state_t sl_led_get_state(const sl_led_t *led_handle);
/** @} (end group led) */
// ******** THE REST OF THE FILE IS DOCUMENTATION ONLY !***********************
/// @addtogroup led LED Driver
/// @{
///
/// @details
///
///
/// @n @section leddrv_intro Introduction
///
/// The LED driver is a platfom level software module that manages the control of
/// various types of LEDs. There are currently two types of LEDs supported by the
/// LED driver:
///
/// @li @ref simple_led
/// @li @ref simple_rgbw_pwm_led
///
/// The common LED functions are called through the generic LED driver, while other
/// functions specific to a certain type of LED are called directly through their own
/// driver.
///
/// @n @section leddrv_config Configuration
///
/// All LED instances are configured using an @ref sl_led_t struct along with a
/// type-specific context struct, and sometimes additional structs. For `sl_led_XXX`
/// functions, the `sl_led_t *led_handle` is used, while for `sl_simple_led_XXX`
/// functions, the `sl_simple_led_context_t *context` is used.
///
/// These structs are automatically generated when an LED is set up using Simplicity
/// Studio's wizard. Specific configuration setups for the various LED types are
/// described in the following sections.
///
/// - [Simple LED Configuration](/gecko-platform/<docspace-docleaf-version>/platform-driver/simple-led#simple-led-configuration)
/// - [RGBW PWM LED Configuration](/gecko-platform/<docspace-docleaf-version>/platform-driver/simple-rgb-pwm-led#rgb-pwm-led-configuration)
///
/// @n @section leddrv_usage Usage
///
/// Once the LED structs are defined, the common LED functions can be called being passed an instance
/// of sl_led_t, which will be redirected to calling the type specific version of that function. The
/// common functions include the following:
///
/// @li @ref sl_led_init
/// @li @ref sl_led_turn_on
/// @li @ref sl_led_turn_off
/// @li @ref sl_led_toggle
/// @li @ref sl_led_get_state
///
/// These functions allow for initializing the LED, turning it on and off, toggling it, and retrieving
/// its current state (on/off). Other functions specific to certain types of LEDs are called through
/// their respective APIs. The usages of the different types of LEDs are described in detail in the
/// following sections:
///
/// @li @ref simple_led_usage
/// @li @ref rgbw_led_usage
///
/// Ensure that the appropriate context type is used in the function calls:
/// - Use `sl_led_t *led_handle` for `sl_led_XXX` functions.
/// - Use `sl_simple_led_context_t *context` for `sl_simple_led_XXX` functions.
///
/// These distinctions are handled by the Simplicity Studio auto-generated code.
///
/// @} end group led ********************************************************/
#ifdef __cplusplus
}
#endif
#endif // SL_LED_H

View File

@@ -0,0 +1,226 @@
/***************************************************************************//**
* @file
* @brief Simple LED Driver
*******************************************************************************
* # License
* <b>Copyright 2019 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* 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.
*
******************************************************************************/
#ifndef SL_SIMPLE_LED_H
#define SL_SIMPLE_LED_H
#include "sl_led.h"
#include "sl_gpio.h"
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/***************************************************************************//**
* @addtogroup led
* @{
******************************************************************************/
/***************************************************************************//**
* @addtogroup simple_led Simple LED Driver
* @brief Simple LED Driver can be used to execute basic LED functionalities
* such as on, off, toggle, or retrive the on/off status on Silicon Labs
* devices. Subsequent sections provide more insight into this module.
* @{
******************************************************************************/
/*******************************************************************************
****************************** DEFINES ************************************
******************************************************************************/
#define SL_SIMPLE_LED_POLARITY_ACTIVE_LOW 0U ///< LED Active polarity Low
#define SL_SIMPLE_LED_POLARITY_ACTIVE_HIGH 1U ///< LED Active polarity High
/*******************************************************************************
***************************** DATA TYPES **********************************
******************************************************************************/
typedef uint8_t sl_led_polarity_t; ///< LED GPIO polarities (active high/low)
/// A Simple LED instance
typedef struct {
sl_gpio_port_t port; ///< LED port
uint8_t pin; ///< LED pin
sl_led_polarity_t polarity; ///< Initial state of LED
} sl_simple_led_context_t;
/*******************************************************************************
***************************** PROTOTYPES **********************************
******************************************************************************/
/***************************************************************************//**
* Initialize the simple LED driver.
*
* @param[in] led_handle Pointer to simple-led specific data:
* - sl_simple_led_context_t
*
* @return Status Code:
* - SL_STATUS_OK
******************************************************************************/
sl_status_t sl_simple_led_init(void *led_handle);
/***************************************************************************//**
* Turn on a simple LED.
*
* @param[in] led_handle Pointer to simple-led specific data:
* - sl_simple_led_context_t
*
******************************************************************************/
void sl_simple_led_turn_on(void *led_handle);
/***************************************************************************//**
* Turn off a simple LED.
*
* @param[in] led_handle Pointer to simple-led specific data:
* - sl_simple_led_context_t
*
******************************************************************************/
void sl_simple_led_turn_off(void *led_handle);
/***************************************************************************//**
* Toggle a simple LED.
*
* @param[in] led_handle Pointer to simple-led specific data:
* - sl_simple_led_context_t
*
******************************************************************************/
void sl_simple_led_toggle(void *led_handle);
/***************************************************************************//**
* Get the current state of the simple LED.
*
* @param[in] led_handle Pointer to simple-led specific data:
* - sl_simple_led_context_t
*
* @return sl_led_state_t Current state of simple LED. 1 for on, 0 for off
******************************************************************************/
sl_led_state_t sl_simple_led_get_state(void *led_handle);
/** @} (end group simple_led) */
/** @} (end group led) */
// ******** THE REST OF THE FILE IS DOCUMENTATION ONLY !***********************
/// @addtogroup simple_led Simple LED Driver
/// @{
///
/// @details
///
///
/// @n @section simple_led_intro Introduction
///
/// The Simple LED driver is a module of the LED driver that provides the functionality
/// to control simple on/off LEDs.
///
/// @n @section simple_led_config Simple LED Configuration
///
/// Simple LEDs use the @ref sl_led_t struct and their @ref sl_simple_led_context_t
/// struct. These are automatically generated into the following files, as well as
/// instance specific headers with macro definitions in them. The samples below
/// are for a single instance called "inst0".
///
/// @code{.c}
///// sl_simple_led_instances.c
///
///#include "sl_simple_led.h"
///#include "sl_gpio.h"
///#include "sl_simple_led_inst0_config.h"
///
///sl_simple_led_context_t simple_inst0_context = {
/// .port = SL_SIMPLE_LED_INST0_PORT,
/// .pin = SL_SIMPLE_LED_INST0_PIN,
/// .polarity = SL_SIMPLE_LED_INST0_POLARITY,
///};
///
///const sl_led_t sl_led_inst0 = {
/// .context = &simple_inst0_context,
/// .init = sl_simple_led_init,
/// .turn_on = sl_simple_led_turn_on,
/// .turn_off = sl_simple_led_turn_off,
/// .toggle = sl_simple_led_toggle,
/// .get_state = sl_simple_led_get_state,
///};
///
///void sl_simple_led_init_instances(void)
///{
/// sl_led_init(&sl_led_inst0);
///}
/// @endcode
///
/// @note The sl_simple_led_instances.c file is shown with only one instance, but if more
/// were in use they would all appear in this .c file.
///
/// @code{.c}
///// sl_simple_led_instances.h
///
///#ifndef SL_SIMPLE_LED_INSTANCES_H
///#define SL_SIMPLE_LED_INSTANCES_H
///
///#include "sl_simple_led.h"
///
///extern const sl_led_t sl_led_inst0;
///
///void sl_simple_led_init_instances(void);
///
///#endif // SL_SIMPLE_LED_INIT_H
/// @endcode
///
/// @note The sl_simple_led_instances.h file is shown with only one instance, but if more
/// were in use they would all appear in this .h file.
///
/// @n @section simple_led_usage Simple LED Usage
///
/// The simple LED driver is for LEDs with basic on off functionality, and there
/// are no additional functions beyond those in the common driver. The LEDs can be
/// turned on and off, toggled, and their on/off state can be retrieved. The following
/// code shows how to control these LEDs. An LED should always be initialized before
/// calling any other functions with it.
///
/// @code{.c}
///// initialize simple LED
///sl_simple_led_init(&simple_led_inst0);
///
///// turn on simple LED, turn off simple LED, and toggle the simple LED
///sl_simple_led_turn_on(&simple_led_inst0);
///sl_simple_led_turn_off(&simple_led_inst0);
///sl_simple_led_toggle(&simple_led_inst0);
///
///// get the state of the simple LED
///sl_led_state_t state = sl_simple_led_get_state(&simple_led_instance0);
/// @endcode
///
/// @} end group simple_led ********************************************************/
#ifdef __cplusplus
}
#endif
#endif // SL_SIMPLE_LED_H

View File

@@ -0,0 +1,56 @@
/***************************************************************************//**
* @file
* @brief LED Driver
*******************************************************************************
* # License
* <b>Copyright 2019 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* 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 "sl_led.h"
sl_status_t sl_led_init(const sl_led_t *led_handle)
{
return led_handle->init(led_handle->context);
}
void sl_led_turn_on(const sl_led_t *led_handle)
{
led_handle->turn_on(led_handle->context);
}
void sl_led_turn_off(const sl_led_t *led_handle)
{
led_handle->turn_off(led_handle->context);
}
void sl_led_toggle(const sl_led_t *led_handle)
{
led_handle->toggle(led_handle->context);
}
sl_led_state_t sl_led_get_state(const sl_led_t *led_handle)
{
return led_handle->get_state(led_handle->context);
}

View File

@@ -0,0 +1,104 @@
/***************************************************************************//**
* @file
* @brief Simple LED Driver
*******************************************************************************
* # License
* <b>Copyright 2019 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* 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 "sl_simple_led.h"
#include "sl_gpio.h"
#include "sl_clock_manager.h"
sl_status_t sl_simple_led_init(void *context)
{
sl_simple_led_context_t *led = context;
sl_clock_manager_enable_bus_clock(SL_BUS_CLOCK_GPIO);
sl_gpio_t gpio;
gpio.port = led->port;
gpio.pin = led->pin;
sl_gpio_set_pin_mode(&gpio,
SL_GPIO_MODE_PUSH_PULL,
!led->polarity);
return SL_STATUS_OK;
}
void sl_simple_led_turn_on(void *context)
{
sl_simple_led_context_t *led = context;
sl_gpio_t gpio;
gpio.port = led->port;
gpio.pin = led->pin;
if (led->polarity == SL_SIMPLE_LED_POLARITY_ACTIVE_LOW) {
sl_gpio_clear_pin(&gpio);
} else {
sl_gpio_set_pin(&gpio);
}
}
void sl_simple_led_turn_off(void *context)
{
sl_simple_led_context_t *led = context;
sl_gpio_t gpio;
gpio.port = led->port;
gpio.pin = led->pin;
if (led->polarity == SL_SIMPLE_LED_POLARITY_ACTIVE_LOW) {
sl_gpio_set_pin(&gpio);
} else {
sl_gpio_clear_pin(&gpio);
}
}
void sl_simple_led_toggle(void *context)
{
sl_simple_led_context_t *led = context;
sl_gpio_t gpio;
gpio.port = led->port;
gpio.pin = led->pin;
sl_gpio_toggle_pin(&gpio);
}
sl_led_state_t sl_simple_led_get_state(void *context)
{
sl_simple_led_context_t *led = context;
sl_led_state_t value;
sl_gpio_t gpio;
bool pin_value;
gpio.port = led->port;
gpio.pin = led->pin;
sl_gpio_get_pin_output(&gpio, &pin_value);
value = (sl_led_state_t)pin_value;
if (led->polarity == SL_SIMPLE_LED_POLARITY_ACTIVE_LOW) {
return !value;
} else {
return value;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,36 @@
/***************************************************************************//**
* @file
* @brief Emlib peripheral API "assert" implementation.
*******************************************************************************
* # License
* <b>Copyright 2018 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* 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.
*
******************************************************************************/
#ifndef EM_ASSERT_H
#define EM_ASSERT_H
#include "sl_assert.h"
#endif /* EM_ASSERT_H */

View File

@@ -0,0 +1,473 @@
/***************************************************************************//**
* @file
* @brief Backup Real Time Counter (BURTC) peripheral API
*******************************************************************************
* # License
* <b>Copyright 2018 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* 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.
*
******************************************************************************/
#ifndef EM_BURTC_H
#define EM_BURTC_H
#include "em_device.h"
#if defined(BURTC_PRESENT)
#include <stdbool.h>
#include "sl_assert.h"
#include "em_bus.h"
#ifdef __cplusplus
extern "C" {
#endif
/***************************************************************************//**
* @addtogroup burtc
* @{
******************************************************************************/
/*******************************************************************************
******************************* DEFINES ***********************************
******************************************************************************/
/** BURTC clock divisors. These values are valid for the BURTC prescaler. */
#define burtcClkDiv_1 1 /**< Divide clock by 1. */
#define burtcClkDiv_2 2 /**< Divide clock by 2. */
#define burtcClkDiv_4 4 /**< Divide clock by 4. */
#define burtcClkDiv_8 8 /**< Divide clock by 8. */
#define burtcClkDiv_16 16 /**< Divide clock by 16. */
#define burtcClkDiv_32 32 /**< Divide clock by 32. */
#define burtcClkDiv_64 64 /**< Divide clock by 64. */
#define burtcClkDiv_128 128 /**< Divide clock by 128. */
/*******************************************************************************
******************************** ENUMS ************************************
******************************************************************************/
#if defined(_SILICON_LABS_32B_SERIES_0)
/** BURTC clock selection. */
typedef enum {
/** Ultra low frequency (1 kHz) clock. */
burtcClkSelULFRCO = BURTC_CTRL_CLKSEL_ULFRCO,
/** Low frequency RC oscillator. */
burtcClkSelLFRCO = BURTC_CTRL_CLKSEL_LFRCO,
/** Low frequency crystal oscillator. */
burtcClkSelLFXO = BURTC_CTRL_CLKSEL_LFXO
} BURTC_ClkSel_TypeDef;
/** BURTC mode of operation. */
typedef enum {
/** Disable BURTC */
burtcModeDisable = BURTC_CTRL_MODE_DISABLE,
/** Enable and start BURTC counter in EM0 to EM2. */
burtcModeEM2 = BURTC_CTRL_MODE_EM2EN,
/** Enable and start BURTC counter in EM0 to EM3. */
burtcModeEM3 = BURTC_CTRL_MODE_EM3EN,
/** Enable and start BURTC counter in EM0 to EM4. */
burtcModeEM4 = BURTC_CTRL_MODE_EM4EN,
} BURTC_Mode_TypeDef;
/** BURTC low power mode. */
typedef enum {
/** Low Power Mode is disabled. */
burtcLPDisable = BURTC_LPMODE_LPMODE_DISABLE,
/** Low Power Mode is always enabled. */
burtcLPEnable = BURTC_LPMODE_LPMODE_ENABLE,
/** Low Power Mode when system enters backup mode. */
burtcLPBU = BURTC_LPMODE_LPMODE_BUEN
} BURTC_LP_TypeDef;
#endif
/*******************************************************************************
******************************* STRUCTS ***********************************
******************************************************************************/
#if defined(_SILICON_LABS_32B_SERIES_0)
/** BURTC initialization structure for Series 0 devices. */
typedef struct {
bool enable; /**< Enable BURTC after initialization (starts counter). */
BURTC_Mode_TypeDef mode; /**< Configure energy mode operation. */
bool debugRun; /**< If true, counter will keep running under debug halt. */
BURTC_ClkSel_TypeDef clkSel; /**< Select clock source. */
uint32_t clkDiv; /**< Clock divider; for ULFRCO 1Khz or 2kHz operation. */
uint32_t lowPowerComp; /**< Number of least significant clock bits to ignore in low power mode. */
bool timeStamp; /**< Enable time stamp on entering backup power domain. */
bool compare0Top; /**< Set if Compare Value 0 is also top value (counter restart). */
BURTC_LP_TypeDef lowPowerMode; /**< Low power operation mode, requires LFXO or LFRCO. */
} BURTC_Init_TypeDef;
/** Default configuration for BURTC initialization structure. */
#define BURTC_INIT_DEFAULT \
{ \
true, \
burtcModeEM2, \
false, \
burtcClkSelULFRCO, \
burtcClkDiv_1, \
0, \
true, \
false, \
burtcLPDisable, \
}
#elif defined(_SILICON_LABS_32B_SERIES_2)
/** BURTC initialization structure for Series 2 devices. */
typedef struct {
bool start; /**< Start BURTC after initialization */
bool debugRun; /**< If true, counter will keep running under debug halt */
uint32_t clkDiv; /**< Clock divider. Supported range is 1-32768 */
bool compare0Top; /**< Set if Compare Value 0 is also top value (counter restart) */
bool em4comp; /**< Enable EM4 wakeup on compare match. */
bool em4overflow; /**< Enable EM4 wakeup on counter overflow. */
} BURTC_Init_TypeDef;
/** Default configuration for BURTC init structure */
#define BURTC_INIT_DEFAULT \
{ \
true, \
false, \
1, \
0, \
false, \
false, \
}
#endif
/*******************************************************************************
***************************** PROTOTYPES **********************************
******************************************************************************/
/***************************************************************************//**
* @brief
* Clear one or more pending BURTC interrupts.
*
* @param[in] flags
* BURTC interrupt sources to clear. Use a set of interrupt flags OR-ed
* together to clear multiple interrupt sources for the BURTC module
* (BURTC_IFS_nnn).
******************************************************************************/
__STATIC_INLINE void BURTC_IntClear(uint32_t flags)
{
#if defined(BURTC_HAS_SET_CLEAR)
BURTC->IF_CLR = flags;
#else
BURTC->IFC = flags;
#endif
}
/***************************************************************************//**
* @brief
* Disable one or more BURTC interrupts.
*
* @param[in] flags
* BURTC interrupt sources to disable. Use a set of interrupt flags OR-ed
* together to disable multiple interrupt sources for the BURTC module
* (BURTC_IFS_nnn).
******************************************************************************/
__STATIC_INLINE void BURTC_IntDisable(uint32_t flags)
{
#if defined(BURTC_HAS_SET_CLEAR)
BURTC->IEN_CLR = flags;
#else
BURTC->IEN &= ~(flags);
#endif
}
/***************************************************************************//**
* @brief
* Enable one or more BURTC interrupts.
*
* @note
* Depending on use, a pending interrupt may already be set prior to
* enabling the interrupt. Consider using BURTC_IntClear() prior to enabling
* if a pending interrupt should be ignored.
*
* @param[in] flags
* BURTC interrupt sources to enable. Use a set of interrupt flags OR-ed
* together to set multiple interrupt sources for the BURTC module
* (BURTC_IFS_nnn).
******************************************************************************/
__STATIC_INLINE void BURTC_IntEnable(uint32_t flags)
{
#if defined(BURTC_HAS_SET_CLEAR)
BURTC->IEN_SET = flags;
#else
BURTC->IEN |= flags;
#endif
}
/***************************************************************************//**
* @brief
* Get pending BURTC interrupt flags.
*
* @note
* This function does not clear the event bits.
*
* @return
* Pending BURTC interrupt sources. Returns a set of interrupt flags OR-ed
* together for multiple interrupt sources in the BURTC module (BURTC_IFS_nnn).
******************************************************************************/
__STATIC_INLINE uint32_t BURTC_IntGet(void)
{
return BURTC->IF;
}
/***************************************************************************//**
* @brief
* Get enabled and pending BURTC interrupt flags.
*
* @note
* The event bits are not cleared by the use of this function.
*
* @return
* Pending BURTC interrupt sources that is also enabled. Returns a set of
* interrupt flags OR-ed together for multiple interrupt sources in the
* BURTC module (BURTC_IFS_nnn).
******************************************************************************/
__STATIC_INLINE uint32_t BURTC_IntGetEnabled(void)
{
uint32_t tmp;
/* Get enabled interrupts */
tmp = BURTC->IEN;
/* Return set interrupts */
return BURTC->IF & tmp;
}
/***************************************************************************//**
* @brief
* Set one or more pending BURTC interrupts from SW.
*
* @param[in] flags
* BURTC interrupt sources to set to pending. Use a set of interrupt flags
* OR-ed together to set multiple interrupt sources for the BURTC module
* (BURTC_IFS_nnn).
******************************************************************************/
__STATIC_INLINE void BURTC_IntSet(uint32_t flags)
{
#if defined(BURTC_HAS_SET_CLEAR)
BURTC->IF_SET = flags;
#else
BURTC->IFS = flags;
#endif
}
/***************************************************************************//**
* @brief
* Status of BURTC RAM, timestamp and LP Mode
*
* @return A mask logically OR-ed status bits
******************************************************************************/
__STATIC_INLINE uint32_t BURTC_Status(void)
{
return BURTC->STATUS;
}
#if defined(BURTC_CMD_CLRSTATUS)
/***************************************************************************//**
* @brief
* Clear and reset BURTC status register
******************************************************************************/
__STATIC_INLINE void BURTC_StatusClear(void)
{
BURTC->CMD = BURTC_CMD_CLRSTATUS;
}
#endif
/***************************************************************************//**
* @brief
* Wait for the BURTC to complete all synchronization of register changes
* and commands.
******************************************************************************/
__STATIC_INLINE void BURTC_SyncWait(void)
{
#if defined(_SILICON_LABS_32B_SERIES_2)
while ((BURTC->EN != 0U) && (BURTC->SYNCBUSY != 0U)) {
/* Wait for previous synchronization to finish */
}
#else
while (BURTC->SYNCBUSY != 0U) {
/* Wait for previous synchronization to finish */
}
#endif
}
#if defined(_SILICON_LABS_32B_SERIES_2)
/***************************************************************************//**
* @brief
* Start BURTC counter.
*
* This function will send a start command to the BURTC peripheral. The BURTC
* peripheral will use some LF clock ticks before the command is executed.
* The @ref BURTC_SyncWait() function can be used to wait for the start command
* to be executed.
*
* @note
* This function requires the BURTC to be enabled.
******************************************************************************/
__STATIC_INLINE void BURTC_Start(void)
{
BURTC_SyncWait();
BURTC->CMD = BURTC_CMD_START;
}
/***************************************************************************//**
* @brief
* Stop the BURTC counter.
*
* This function will send a stop command to the BURTC peripheral. The BURTC
* peripheral will use some LF clock ticks before the command is executed.
* The @ref BURTC_SyncWait() function can be used to wait for the stop command
* to be executed.
*
* @note
* This function requires the BURTC to be enabled.
******************************************************************************/
__STATIC_INLINE void BURTC_Stop(void)
{
BURTC_SyncWait();
BURTC->CMD = BURTC_CMD_STOP;
}
#endif
/***************************************************************************//**
* @brief Get BURTC counter.
*
* @return
* BURTC counter value
******************************************************************************/
__STATIC_INLINE uint32_t BURTC_CounterGet(void)
{
return BURTC->CNT;
}
#if defined(_SILICON_LABS_32B_SERIES_0)
/***************************************************************************//**
* @brief Get BURTC timestamp for entering BU.
*
* @return
* BURTC Time Stamp value
******************************************************************************/
__STATIC_INLINE uint32_t BURTC_TimestampGet(void)
{
return BURTC->TIMESTAMP;
}
/***************************************************************************//**
* @brief Freeze register updates until enabled.
* @param[in] enable If true, registers are not updated until enabled again.
******************************************************************************/
__STATIC_INLINE void BURTC_FreezeEnable(bool enable)
{
BUS_RegBitWrite(&BURTC->FREEZE, _BURTC_FREEZE_REGFREEZE_SHIFT, enable);
}
/***************************************************************************//**
* @brief Shut down power to retention register bank.
* @param[in] enable
* If true, shuts off power to retention registers.
* @note
* When power retention is disabled, it can't be enabled again (until
* reset).
******************************************************************************/
__STATIC_INLINE void BURTC_Powerdown(bool enable)
{
BUS_RegBitWrite(&BURTC->POWERDOWN, _BURTC_POWERDOWN_RAM_SHIFT, enable);
}
/***************************************************************************//**
* @brief
* Set a value in one of the retention registers.
*
* @param[in] num
* Register to set
* @param[in] data
* Value to put into register
******************************************************************************/
__STATIC_INLINE void BURTC_RetRegSet(uint32_t num, uint32_t data)
{
EFM_ASSERT(num <= 127);
BURTC->RET[num].REG = data;
}
/***************************************************************************//**
* @brief
* Read a value from one of the retention registers.
*
* @param[in] num
* Retention Register to read
*
* @return
* Value of the retention register
******************************************************************************/
__STATIC_INLINE uint32_t BURTC_RetRegGet(uint32_t num)
{
EFM_ASSERT(num <= 127);
return BURTC->RET[num].REG;
}
#endif
/***************************************************************************//**
* @brief
* Lock BURTC registers, which will protect from writing new config settings.
******************************************************************************/
__STATIC_INLINE void BURTC_Lock(void)
{
BURTC->LOCK = 0x0;
}
/***************************************************************************//**
* @brief
* Unlock BURTC registers, which will enable write access to change configuration.
******************************************************************************/
__STATIC_INLINE void BURTC_Unlock(void)
{
BURTC->LOCK = BURTC_LOCK_LOCKKEY_UNLOCK;
}
void BURTC_Reset(void);
void BURTC_Init(const BURTC_Init_TypeDef *burtcInit);
void BURTC_Enable(bool enable);
void BURTC_CounterReset(void);
void BURTC_CompareSet(unsigned int comp, uint32_t value);
uint32_t BURTC_CompareGet(unsigned int comp);
#if defined(_BURTC_CTRL_MASK)
uint32_t BURTC_ClockFreqGet(void);
#endif
/** @} (end addtogroup burtc) */
#ifdef __cplusplus
}
#endif
#endif /* BURTC_PRESENT */
#endif /* EM_BURTC_H */

View File

@@ -0,0 +1,350 @@
/***************************************************************************//**
* @file
* @brief RAM and peripheral bit-field set and clear API
*******************************************************************************
* # License
* <b>Copyright 2018 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* 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.
*
******************************************************************************/
#ifndef EM_BUS_H
#define EM_BUS_H
#include "sl_assert.h"
#include "sl_core.h"
#include "em_device.h"
#ifdef __cplusplus
extern "C" {
#endif
/***************************************************************************//**
* @addtogroup bus BUS - Bitfield Read/Write
* @brief BUS register and RAM bit/field read/write API
* @details
* API to perform bit-band and field set/clear access to RAM and peripherals.
* @{
******************************************************************************/
/***************************************************************************//**
* @brief
* Perform a single-bit write operation on a 32-bit word in RAM.
*
* @details
* This function uses Cortex-M bit-banding hardware to perform an atomic
* read-modify-write operation on a single bit write on a 32-bit word in RAM.
* See the reference manual for more details about bit-banding.
*
* @note
* This function is atomic on Cortex-M cores with bit-banding support. Bit-
* banding is a multi cycle read-modify-write bus operation. RAM bit-banding is
* performed using the memory alias region at BITBAND_RAM_BASE.
*
* @param[in] addr An ddress of a 32-bit word in RAM.
*
* @param[in] bit A bit position to write, 0-31.
*
* @param[in] val A value to set bit to, 0 or 1.
******************************************************************************/
__STATIC_INLINE void BUS_RamBitWrite(volatile uint32_t *addr,
unsigned int bit,
unsigned int val)
{
#if defined(BITBAND_RAM_BASE)
uint32_t aliasAddr =
BITBAND_RAM_BASE + (((uint32_t)addr - SRAM_BASE) * (uint32_t) 32) + (bit * (uint32_t) 4);
*(volatile uint32_t *)aliasAddr = (uint32_t)val;
#else
uint32_t tmp = *addr;
/* Make sure val is not more than 1 because only one bit needs to be set. */
*addr = (tmp & ~(1UL << bit)) | ((val & 1UL) << bit);
#endif
}
/***************************************************************************//**
* @brief
* Perform a single-bit read operation on a 32-bit word in RAM.
*
* @details
* This function uses Cortex-M bit-banding hardware to perform an atomic
* read operation on a single register bit. See the
* reference manual for more details about bit-banding.
*
* @note
* This function is atomic on Cortex-M cores with bit-banding support.
* RAM bit-banding is performed using the memory alias region
* at BITBAND_RAM_BASE.
*
* @param[in] addr RAM address.
*
* @param[in] bit A bit position to read, 0-31.
*
* @return
* The requested bit shifted to bit position 0 in the return value.
******************************************************************************/
__STATIC_INLINE unsigned int BUS_RamBitRead(volatile const uint32_t *addr,
unsigned int bit)
{
#if defined(BITBAND_RAM_BASE)
uint32_t aliasAddr =
BITBAND_RAM_BASE + (((uint32_t)addr - SRAM_BASE) * (uint32_t) 32) + (bit * (uint32_t) 4);
return *(volatile uint32_t *)aliasAddr;
#else
return ((*addr) >> bit) & 1UL;
#endif
}
/***************************************************************************//**
* @brief
* Perform a single-bit write operation on a peripheral register.
*
* @details
* This function uses Cortex-M bit-banding hardware to perform an atomic
* read-modify-write operation on a single register bit. See the
* reference manual for more details about bit-banding.
*
* @note
* This function is atomic on Cortex-M cores with bit-banding support. Bit-
* banding is a multi cycle read-modify-write bus operation. Peripheral register
* bit-banding is performed using the memory alias region at BITBAND_PER_BASE.
*
* @param[in] addr A peripheral register address.
*
* @param[in] bit A bit position to write, 0-31.
*
* @param[in] val A value to set bit to, 0 or 1.
******************************************************************************/
__STATIC_INLINE void BUS_RegBitWrite(volatile uint32_t *addr,
unsigned int bit,
unsigned int val)
{
EFM_ASSERT(bit < 32U);
#if defined(PER_REG_BLOCK_SET_OFFSET) && defined(PER_REG_BLOCK_CLR_OFFSET)
uint32_t aliasAddr;
if (val != 0U) {
aliasAddr = (uint32_t)addr + PER_REG_BLOCK_SET_OFFSET;
} else {
aliasAddr = (uint32_t)addr + PER_REG_BLOCK_CLR_OFFSET;
}
*(volatile uint32_t *)aliasAddr = 1UL << bit;
#elif defined(BITBAND_PER_BASE)
uint32_t aliasAddr =
BITBAND_PER_BASE + (((uint32_t)addr - PER_MEM_BASE) * (uint32_t) 32) + (bit * (uint32_t) 4);
*(volatile uint32_t *)aliasAddr = (uint32_t)val;
#else
uint32_t tmp = *addr;
/* Make sure val is not more than 1 because only one bit needs to be set. */
*addr = (tmp & ~(1 << bit)) | ((val & 1) << bit);
#endif
}
/***************************************************************************//**
* @brief
* Perform a single-bit read operation on a peripheral register.
*
* @details
* This function uses Cortex-M bit-banding hardware to perform an atomic
* read operation on a single register bit. See the
* reference manual for more details about bit-banding.
*
* @note
* This function is atomic on Cortex-M cores with bit-banding support.
* Peripheral register bit-banding is performed using the memory alias
* region at BITBAND_PER_BASE.
*
* @param[in] addr A peripheral register address.
*
* @param[in] bit A bit position to read, 0-31.
*
* @return
* The requested bit shifted to bit position 0 in the return value.
******************************************************************************/
__STATIC_INLINE unsigned int BUS_RegBitRead(volatile const uint32_t *addr,
unsigned int bit)
{
#if defined(BITBAND_PER_BASE)
uint32_t aliasAddr =
BITBAND_PER_BASE + (((uint32_t)addr - PER_MEM_BASE) * (uint32_t)32) + (bit * (uint32_t) 4);
return *(volatile uint32_t *)aliasAddr;
#else
return ((*addr) >> bit) & 1UL;
#endif
}
/***************************************************************************//**
* @brief
* Perform a masked set operation on a peripheral register address.
*
* @details
* A peripheral register masked set provides a single-cycle and atomic set
* operation of a bit-mask in a peripheral register. All 1s in the mask are
* set to 1 in the register. All 0s in the mask are not changed in the
* register.
* RAMs and special peripherals are not supported. See the
* reference manual for more details about the peripheral register field set.
*
* @note
* This function is single-cycle and atomic on cores with peripheral bit set
* and clear support. It uses the memory alias region at PER_BITSET_MEM_BASE.
*
* @param[in] addr A peripheral register address.
*
* @param[in] mask A mask to set.
******************************************************************************/
__STATIC_INLINE void BUS_RegMaskedSet(volatile uint32_t *addr,
uint32_t mask)
{
#if defined(PER_REG_BLOCK_SET_OFFSET)
uint32_t aliasAddr = (uint32_t)addr + PER_REG_BLOCK_SET_OFFSET;
*(volatile uint32_t *)aliasAddr = mask;
#elif defined(PER_BITSET_MEM_BASE)
uint32_t aliasAddr = PER_BITSET_MEM_BASE + ((uint32_t)addr - PER_MEM_BASE);
*(volatile uint32_t *)aliasAddr = mask;
#else
CORE_DECLARE_IRQ_STATE;
CORE_ENTER_CRITICAL();
*addr |= mask;
CORE_EXIT_CRITICAL();
#endif
}
/***************************************************************************//**
* @brief
* Perform a masked clear operation on the peripheral register address.
*
* @details
* A peripheral register masked clear provides a single-cycle and atomic clear
* operation of a bit-mask in a peripheral register. All 1s in the mask are
* set to 0 in the register.
* All 0s in the mask are not changed in the register.
* RAMs and special peripherals are not supported. See the
* reference manual for more details about the peripheral register field clear.
*
* @note
* This function is single-cycle and atomic on cores with peripheral bit set
* and clear support. It uses the memory alias region at PER_BITCLR_MEM_BASE.
*
* @param[in] addr A peripheral register address.
*
* @param[in] mask A mask to clear.
******************************************************************************/
__STATIC_INLINE void BUS_RegMaskedClear(volatile uint32_t *addr,
uint32_t mask)
{
#if defined(PER_REG_BLOCK_CLR_OFFSET)
uint32_t aliasAddr = (uint32_t)addr + PER_REG_BLOCK_CLR_OFFSET;
*(volatile uint32_t *)aliasAddr = mask;
#elif defined(PER_BITCLR_MEM_BASE)
uint32_t aliasAddr = PER_BITCLR_MEM_BASE + ((uint32_t)addr - PER_MEM_BASE);
*(volatile uint32_t *)aliasAddr = mask;
#else
CORE_DECLARE_IRQ_STATE;
CORE_ENTER_CRITICAL();
*addr &= ~mask;
CORE_EXIT_CRITICAL();
#endif
}
/***************************************************************************//**
* @brief
* Perform peripheral register masked write.
*
* @details
* This function first reads the peripheral register and updates only bits
* that are set in the mask with content of val. Typically, the mask is a
* bit-field in the register and the value val is within the mask.
*
* @note
* The read-modify-write operation is executed in a critical section to
* guarantee atomicity. Note that atomicity can only be guaranteed if register
* is modified only by the core, and not by other peripherals (like DMA).
*
* @param[in] addr A peripheral register address.
*
* @param[in] mask A peripheral register mask.
*
* @param[in] val A peripheral register value. The value must be shifted to the
correct bit position in the register corresponding to the field
defined by the mask parameter. The register value must be
contained in the field defined by the mask parameter. The
register value is masked to prevent involuntary spillage.
******************************************************************************/
#if defined(__GNUC__) && __GNUC__ >= 10
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wanalyzer-null-dereference"
#endif
__STATIC_INLINE void BUS_RegMaskedWrite(volatile uint32_t *addr,
uint32_t mask,
uint32_t val)
{
CORE_DECLARE_IRQ_STATE;
CORE_ENTER_CRITICAL();
EFM_ASSERT(addr != 0);
*addr = (*addr & ~mask) | (val & mask);
CORE_EXIT_CRITICAL();
}
#if defined(__GNUC__) && __GNUC__ >= 10
#pragma GCC diagnostic pop
#endif
/***************************************************************************//**
* @brief
* Perform a peripheral register masked read.
*
* @details
* Read an unshifted and masked value from a peripheral register.
*
* @note
* This operation is not hardware accelerated.
*
* @param[in] addr A peripheral register address.
*
* @param[in] mask A peripheral register mask.
*
* @return
* An unshifted and masked register value.
******************************************************************************/
__STATIC_INLINE uint32_t BUS_RegMaskedRead(volatile const uint32_t *addr,
uint32_t mask)
{
return *addr & mask;
}
/** @} (end addtogroup bus) */
#ifdef __cplusplus
}
#endif
#endif /* EM_BUS_H */

View File

@@ -0,0 +1,483 @@
/***************************************************************************//**
* @file
* @brief Chip Errata Workarounds
*******************************************************************************
* # License
* <b>Copyright 2018 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* 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.
*
******************************************************************************/
#ifndef EM_CHIP_H
#define EM_CHIP_H
#include "em_device.h"
#include "sl_common.h"
#if defined(_SILICON_LABS_32B_SERIES) && (_SILICON_LABS_32B_SERIES <= 2)
#include "em_system.h"
#endif
#include "em_bus.h"
#if defined(_SILICON_LABS_GECKO_INTERNAL_SDID_80)
#include "em_gpio.h"
#endif
#if defined(_SILICON_LABS_GECKO_INTERNAL_SDID_240)
#include "em_cmu.h"
#endif
#ifdef __cplusplus
extern "C" {
#endif
/***************************************************************************//**
* @addtogroup chip CHIP - Chip Errata Workarounds
* @brief Chip errata workaround APIs
* @details
* API to apply chip errata workarounds at initialization and reset.
* @{
******************************************************************************/
/**************************************************************************//**
* @brief
* Chip initialization routine for revision errata workarounds.
*
* @note
* This function must be called immediately in main().
*
* This initialization function configures the device to a state
* as similar to later revisions as possible to improve software compatibility
* with newer parts. See the device-specific errata for details.
*****************************************************************************/
__STATIC_INLINE void CHIP_Init(void)
{
#if defined(MSC_CACHECMD_INVCACHE)
MSC->CACHECMD = MSC_CACHECMD_INVCACHE;
#elif defined(MSC_CMD_INVCACHE)
MSC->CMD = MSC_CMD_INVCACHE;
#endif
#if defined(_SILICON_LABS_32B_SERIES_0) && defined(_EFM32_GECKO_FAMILY)
uint32_t rev;
SYSTEM_ChipRevision_TypeDef chipRev;
volatile uint32_t *reg;
rev = *(volatile uint32_t *)(0x0FE081FC);
/* Engineering Sample calibration setup. */
if ((rev >> 24) == 0) {
reg = (volatile uint32_t *)0x400CA00C;
*reg &= ~(0x70UL);
/* DREG */
reg = (volatile uint32_t *)0x400C6020;
*reg &= ~(0xE0000000UL);
*reg |= ~(7UL << 25);
}
if ((rev >> 24) <= 3) {
/* DREG */
reg = (volatile uint32_t *)0x400C6020;
*reg &= ~(0x00001F80UL);
/* Update CMU reset values. */
reg = (volatile uint32_t *)0x400C8040;
*reg = 0;
reg = (volatile uint32_t *)0x400C8044;
*reg = 0;
reg = (volatile uint32_t *)0x400C8058;
*reg = 0;
reg = (volatile uint32_t *)0x400C8060;
*reg = 0;
reg = (volatile uint32_t *)0x400C8078;
*reg = 0;
}
SYSTEM_ChipRevisionGet(&chipRev);
if (chipRev.major == 0x01) {
/* Rev A errata handling for EM2/3. Must enable DMA clock to get EM2/3 */
/* to work. This will be fixed in later chip revisions and is only needed for rev A. */
if (chipRev.minor == 00) {
reg = (volatile uint32_t *)0x400C8040;
*reg |= 0x2;
}
/* Rev A+B errata handling for I2C when using EM2/3. USART0 clock must be enabled */
/* after waking up from EM2/EM3 to get I2C to work. This will be fixed in */
/* later chip revisions and is only needed for rev A+B. */
if (chipRev.minor <= 0x01) {
reg = (volatile uint32_t *)0x400C8044;
*reg |= 0x1;
}
}
/* Ensure correct ADC/DAC calibration value. */
rev = *(volatile uint32_t *)0x0FE081F0;
if (rev < 0x4C8ABA00) {
uint32_t cal;
/* Enable ADC/DAC clocks. */
reg = (volatile uint32_t *)0x400C8044UL;
*reg |= (1 << 14 | 1 << 11);
/* Retrive calibration values. */
cal = ((*(volatile uint32_t *)(0x0FE081B4UL) & 0x00007F00UL)
>> 8) << 24;
cal |= ((*(volatile uint32_t *)(0x0FE081B4UL) & 0x0000007FUL)
>> 0) << 16;
cal |= ((*(volatile uint32_t *)(0x0FE081B4UL) & 0x00007F00UL)
>> 8) << 8;
cal |= ((*(volatile uint32_t *)(0x0FE081B4UL) & 0x0000007FUL)
>> 0) << 0;
/* ADC0->CAL = 1.25 reference. */
reg = (volatile uint32_t *)0x40002034UL;
*reg = cal;
/* DAC0->CAL = 1.25 reference. */
reg = (volatile uint32_t *)(0x4000402CUL);
cal = *(volatile uint32_t *)0x0FE081C8UL;
*reg = cal;
/* Turn off ADC/DAC clocks. */
reg = (volatile uint32_t *)0x400C8044UL;
*reg &= ~(1 << 14 | 1 << 11);
}
#endif
#if defined(_SILICON_LABS_32B_SERIES_0) && defined(_EFM32_GIANT_FAMILY)
/****************************/
/* Fix for errata CMU_E113. */
uint8_t prodRev;
SYSTEM_ChipRevision_TypeDef chipRev;
prodRev = SYSTEM_GetProdRev();
SYSTEM_ChipRevisionGet(&chipRev);
// All Giant and Leopard parts except Leopard Rev E
if ((prodRev >= 16) && (chipRev.minor >= 3)
&& !((chipRev.major == 2) && (chipRev.minor == 4))) {
/* This fixes an issue with the LFXO on high temperatures. */
*(volatile uint32_t*)0x400C80C0 =
(*(volatile uint32_t*)0x400C80C0 & ~(1 << 6) ) | (1 << 4);
}
#endif
#if defined(_SILICON_LABS_32B_SERIES_0) && defined(_EFM32_HAPPY_FAMILY)
uint8_t prodRev;
prodRev = SYSTEM_GetProdRev();
if (prodRev <= 129) {
/* This fixes a mistaken internal connection between PC0 and PC4. */
/* This disables an internal pull-down on PC4. */
*(volatile uint32_t*)(0x400C6018) = (1 << 26) | (5 << 0);
/* This disables an internal LDO test signal driving PC4. */
*(volatile uint32_t*)(0x400C80E4) &= ~(1 << 24);
}
#endif
#if defined(_SILICON_LABS_GECKO_INTERNAL_SDID_80)
/****************************
* Fixes for errata GPIO_E201 (slewrate) and
* HFXO high-temperature oscillator startup robustness fix. */
uint32_t port;
uint32_t clkEn;
uint8_t prodRev;
const uint32_t setVal = (0x5 << _GPIO_P_CTRL_SLEWRATEALT_SHIFT)
| (0x5 << _GPIO_P_CTRL_SLEWRATE_SHIFT);
const uint32_t resetVal = _GPIO_P_CTRL_RESETVALUE
& ~(_GPIO_P_CTRL_SLEWRATE_MASK
| _GPIO_P_CTRL_SLEWRATEALT_MASK);
prodRev = SYSTEM_GetProdRev();
SYSTEM_ChipRevision_TypeDef chipRev;
SYSTEM_ChipRevisionGet(&chipRev);
/* This errata is fixed in hardware from PRODREV 0x8F. */
if (prodRev < 0x8F) {
/* Fixes for errata GPIO_E201 (slewrate). */
/* Save HFBUSCLK enable state and enable GPIO clock. */
clkEn = CMU->HFBUSCLKEN0;
CMU->HFBUSCLKEN0 = clkEn | CMU_HFBUSCLKEN0_GPIO;
/* Update slewrate. */
for (port = 0; port <= GPIO_PORT_MAX; port++) {
GPIO->P[port].CTRL = setVal | resetVal;
}
/* Restore HFBUSCLK enable state. */
CMU->HFBUSCLKEN0 = clkEn;
}
/* This errata is fixed in hardware from PRODREV 0x90. */
if (prodRev < 0x90) {
/* HFXO high-temperature oscillator startup robustness fix. */
CMU->HFXOSTARTUPCTRL =
(CMU->HFXOSTARTUPCTRL & ~_CMU_HFXOSTARTUPCTRL_IBTRIMXOCORE_MASK)
| (0x20 << _CMU_HFXOSTARTUPCTRL_IBTRIMXOCORE_SHIFT);
}
if (chipRev.major == 0x01) {
/* Fix for errata EMU_E210 - Potential Power-Down When Entering EM2 */
*(volatile uint32_t *)(EMU_BASE + 0x164) |= 0x4;
}
/****************************
* Fix for errata DCDC_E206.
* Disable bypass limit enabled temporarily in SystemInit() errata
* workaround. */
BUS_RegBitWrite(&EMU->DCDCCLIMCTRL, _EMU_DCDCCLIMCTRL_BYPLIMEN_SHIFT, 0);
#endif
#if defined(_SILICON_LABS_GECKO_INTERNAL_SDID_84)
uint8_t prodRev = SYSTEM_GetProdRev();
/* EM2 current fixes for early samples. */
if (prodRev == 0U) {
*(volatile uint32_t *)(EMU_BASE + 0x190UL) = 0x0000ADE8UL;
*(volatile uint32_t *)(EMU_BASE + 0x198UL) |= (0x1UL << 2);
*(volatile uint32_t *)(EMU_BASE + 0x190UL) = 0x0;
}
if (prodRev < 2U) {
*(volatile uint32_t *)(EMU_BASE + 0x164UL) |= (0x1UL << 13);
}
/* Set optimal LFRCOCTRL VREFUPDATE and enable duty cycling of VREF. */
CMU->LFRCOCTRL = (CMU->LFRCOCTRL & ~_CMU_LFRCOCTRL_VREFUPDATE_MASK)
| CMU_LFRCOCTRL_VREFUPDATE_64CYCLES
| CMU_LFRCOCTRL_ENVREF;
#endif
#if defined(_SILICON_LABS_32B_SERIES_1) \
&& defined(_EFR_DEVICE) && (_SILICON_LABS_GECKO_INTERNAL_SDID >= 84)
MSC->CTRL |= 0x1UL << 8;
#endif
#if defined(_SILICON_LABS_GECKO_INTERNAL_SDID_89)
SYSTEM_ChipRevision_TypeDef chipRev;
SYSTEM_ChipRevisionGet(&chipRev);
if ((chipRev.major > 1) || (chipRev.minor >= 3)) {
/* PLFRCO trim values */
*(volatile uint32_t *)(CMU_BASE + 0x28CUL) = 608;
*(volatile uint32_t *)(CMU_BASE + 0x290UL) = 356250;
*(volatile uint32_t *)(CMU_BASE + 0x2F0UL) = 0x04000118;
*(volatile uint32_t *)(CMU_BASE + 0x2F8UL) = 0x08328400;
}
#endif
/* Charge redist setup (fixed value): LCD->DBGCTRL.CHGRDSTSTR = 1 (reset: 0). */
#if defined(_LCD_DISPCTRL_CHGRDST_MASK)
#if defined(_SILICON_LABS_32B_SERIES_1)
CMU->HFBUSCLKEN0 |= CMU_HFBUSCLKEN0_LE;
CMU->LFACLKEN0 |= CMU_LFACLKEN0_LCD;
*(volatile uint32_t *)(LCD_BASE + 0x034) |= (0x1UL << 12);
CMU->LFACLKEN0 &= ~CMU_LFACLKEN0_LCD;
CMU->HFBUSCLKEN0 &= ~CMU_HFBUSCLKEN0_LE;
#endif
#endif
#if defined(_SILICON_LABS_32B_SERIES_1) \
&& !defined(_SILICON_LABS_GECKO_INTERNAL_SDID_80) \
&& !defined(ERRATA_FIX_EMU_E220_DECBOD_IGNORE)
/* First part of the EMU_E220 DECBOD Errata fix. DECBOD Reset can occur
* during voltage scaling after EM2/3 wakeup. Second part is in em_emu.c */
*(volatile uint32_t *)(EMU_BASE + 0x1A4) |= 0x1f << 10;
#endif
#if defined(_SILICON_LABS_32B_SERIES_2_CONFIG_1)
SYSTEM_ChipRevision_TypeDef chipRev;
SYSTEM_ChipRevisionGet(&chipRev);
if (chipRev.major == 0x01 && (HFXO0->STATUS & HFXO_STATUS_ENS) == 0U) {
/* Change HFXO default peak detector settings. */
*(volatile uint32_t*)(HFXO0_BASE + 0x34U) =
(*(volatile uint32_t*)(HFXO0_BASE + 0x34U) & 0xFF8000FFU)
| 0x00178500U;
/* Change HFXO low power control settings. */
*(volatile uint32_t*)(HFXO0_BASE + 0x30U) =
(*(volatile uint32_t*)(HFXO0_BASE + 0x30U) & 0xFFFF0FFFU)
| 0x0000C000U;
/* Change default SQBUF bias current. */
*(volatile uint32_t*)(HFXO0_BASE + 0x30U) |= 0x700;
}
if (chipRev.major == 0x01 && chipRev.minor == 0x0) {
/* Trigger RAM read for each RAM instance */
volatile uint32_t *dmem = (volatile uint32_t *) DMEM_RAM0_RAM_MEM_BASE;
for (uint32_t i = 0U; i < DMEM_NUM_BANK; i++) {
// Force memory read
*dmem;
dmem += (DMEM_BANK0_SIZE / 4U);
}
}
/* Set TRACE clock to intended reset value. */
CMU->TRACECLKCTRL = (CMU->TRACECLKCTRL & ~_CMU_TRACECLKCTRL_CLKSEL_MASK)
| CMU_TRACECLKCTRL_CLKSEL_HFRCOEM23;
#endif
#if defined(_SILICON_LABS_GECKO_INTERNAL_SDID_205)
#if defined(SL_TRUSTZONE_SECURE)
#define HFRCO_CLK_CFG_CLR_ADDR (0x40012020UL)
#else
#define HFRCO_CLK_CFG_CLR_ADDR (0x50012020UL)
#endif
#define HFRCO_CLK_CFG_CLKOUTDIS0 (0x4UL)
if (SYSTEM_GetProdRev() == 1) {
bool hfrcoClkIsOff = (CMU->CLKEN0 & CMU_CLKEN0_HFRCO0) == 0;
CMU->CLKEN0_SET = CMU_CLKEN0_HFRCO0;
/* Enable HFRCO CLKOUT0. */
*(volatile uint32_t*)(HFRCO_CLK_CFG_CLR_ADDR) = HFRCO_CLK_CFG_CLKOUTDIS0;
if (hfrcoClkIsOff) {
CMU->CLKEN0_CLR = CMU_CLKEN0_HFRCO0;
}
}
#endif
/* PM-3503 */
#if defined(_SILICON_LABS_GECKO_INTERNAL_SDID_210)
{
bool syscfgClkIsOff = ((CMU->CLKEN0 & CMU_CLKEN0_SYSCFG) == 0);
CMU->CLKEN0_SET = CMU_CLKEN0_SYSCFG;
bool dcdcClkIsOff = ((CMU->CLKEN0 & CMU_CLKEN0_DCDC) == 0);
CMU->CLKEN0_SET = CMU_CLKEN0_DCDC;
bool dcdcIsLock = ((DCDC->LOCKSTATUS & DCDC_LOCKSTATUS_LOCK_LOCKED) != 0);
DCDC->LOCK = DCDC_LOCK_LOCKKEY_UNLOCKKEY;
while (DCDC->SYNCBUSY & DCDC_SYNCBUSY_CTRL) {
/* Wait for previous synchronization to finish */
}
DCDC->CTRL_CLR = DCDC_CTRL_MODE;
while ((DCDC->STATUS & DCDC_STATUS_BYPSW) == 0U) {
/* Wait for BYPASS switch enable. */
}
if (dcdcIsLock) {
DCDC->LOCK = ~DCDC_LOCK_LOCKKEY_UNLOCKKEY;
}
if (dcdcClkIsOff) {
CMU->CLKEN0_CLR = CMU_CLKEN0_DCDC;
}
if (syscfgClkIsOff) {
CMU->CLKEN0_CLR = CMU_CLKEN0_SYSCFG;
}
}
#endif
/* PM-5163 */
#if defined(_SILICON_LABS_GECKO_INTERNAL_SDID_215) \
&& defined(_SILICON_LABS_EFR32_2G4HZ_HP_PA_PRESENT) \
&& (_SILICON_LABS_EFR32_2G4HZ_HP_PA_MAX_OUTPUT_DBM == 20)
SYSTEM_ChipRevision_TypeDef chipRev;
SYSTEM_ChipRevisionGet(&chipRev);
if (chipRev.major == 0x01 && chipRev.minor == 0x00) {
bool hfxo0ClkIsOff = (CMU->CLKEN0 & CMU_CLKEN0_HFXO0) == 0;
CMU->CLKEN0_SET = CMU_CLKEN0_HFXO0;
*(volatile uint32_t*)(HFXO0_BASE + 0x0034UL) =
(*(volatile uint32_t*)(HFXO0_BASE + 0x0034UL) & 0xE3FFFFFFUL)
| 0x0C000000UL;
if (hfxo0ClkIsOff) {
CMU->CLKEN0_CLR = CMU_CLKEN0_HFXO0;
}
}
#endif
#if defined(_SILICON_LABS_GECKO_INTERNAL_SDID_240)
// Enable ICache out of reset.
CMU->CLKEN1_SET = _CMU_CLKEN1_ICACHE0_MASK;
ICACHE0->CTRL_CLR = _ICACHE_CTRL_CACHEDIS_MASK;
CMU->CLKEN1_CLR = _CMU_CLKEN1_ICACHE0_MASK;
CMU->CLKEN0_SET = _CMU_CLKEN0_HFRCO0_MASK;
if (((HFRCO0->CAL & _HFRCO_CAL_TUNING_MASK) >> _HFRCO_CAL_TUNING_SHIFT) == _HFRCO_CAL_TUNING_MASK) {
CMU_HFRCODPLLBandSet(cmuHFRCODPLLFreq_19M0Hz);
}
CMU->CLKEN0_CLR = _CMU_CLKEN0_HFRCO0_MASK;
#endif
}
/**************************************************************************//**
* @brief
* Chip reset routine with errata workarounds.
*
* @note
* This function should be called to reset the chip. It does not return.
*
* This function applies any errata workarounds needed to cleanly reset the
* device and then performs a system reset. See the device-specific errata for
* details.
*****************************************************************************/
__STATIC_INLINE void CHIP_Reset(void)
{
#if defined(_EFR_DEVICE) && defined(_SILICON_LABS_GECKO_INTERNAL_SDID_80)
/****************************
* Workaround for errata DCDC_E206.
* Disable radio interference minimization features when resetting */
// Ensure access to EMU registers
EMU->LOCK = EMU_LOCK_LOCKKEY_UNLOCK;
EMU->PWRLOCK = EMU_PWRLOCK_LOCKKEY_LOCK;
// No need to do anything if the DCDC is not powering DVDD
if ((EMU->PWRCFG & _EMU_PWRCFG_PWRCFG_MASK) == EMU_PWRCFG_PWRCFG_DCDCTODVDD) {
// Make sure radio cannot accidentally re-enable features
*(volatile uint32_t *)(0x40084040UL) = 0x1UL;
// If DCDC is in use, disable features
uint32_t dcdcMode = EMU->DCDCCTRL & _EMU_DCDCCTRL_DCDCMODE_MASK;
if ((dcdcMode == EMU_DCDCCTRL_DCDCMODE_LOWNOISE)
|| (dcdcMode == EMU_DCDCCTRL_DCDCMODE_LOWPOWER)) {
BUS_RegBitWrite((volatile uint32_t *)(0x400E3060UL), 28UL, 0);
BUS_RegBitWrite((volatile uint32_t *)(0x400E3074UL), 0, 0);
}
}
#endif
NVIC_SystemReset();
}
/** @} (end addtogroup chip) */
#ifdef __cplusplus
}
#endif
#endif /* EM_CHIP_H */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,184 @@
/***************************************************************************//**
* @file
* @brief CMU Compatibility Header
*******************************************************************************
* # License
* <b>Copyright 2020 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* 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.
*
******************************************************************************/
#ifndef EM_CMU_COMPAT_H
#define EM_CMU_COMPAT_H
#if defined(_SILICON_LABS_32B_SERIES_2_CONFIG_2)
#define CMU_IF_CALRDYIF CMU_IF_CALRDY
#define _CMU_IF_CALRDYIF_SHIFT _CMU_IF_CALRDY_SHIFT
#define _CMU_IF_CALRDYIF_MASK _CMU_IF_CALRDY_MASK
#define _CMU_IF_CALRDYIF_DEFAULT _CMU_IF_CALRDY_DEFAULT
#define CMU_IF_CALRDYIF_DEFAULT CMU_IF_CALRDY_DEFAULT
#define CMU_IF_CALOFIF CMU_IF_CALOF
#define _CMU_IF_CALOFIF_SHIFT _CMU_IF_CALOF_SHIFT
#define _CMU_IF_CALOFIF_MASK _CMU_IF_CALOF_MASK
#define _CMU_IF_CALOFIF_DEFAULT _CMU_IF_CALOF_DEFAULT
#define CMU_IF_CALOFIF_DEFAULT CMU_IF_CALOF_DEFAULT
#define CMU_IEN_CALRDYIEN CMU_IEN_CALRDY
#define _CMU_IEN_CALRDYIEN_SHIFT _CMU_IEN_CALRDY_SHIFT
#define _CMU_IEN_CALRDYIEN_MASK _CMU_IEN_CALRDY_MASK
#define _CMU_IEN_CALRDYIEN_DEFAULT _CMU_IEN_CALRDY_DEFAULT
#define CMU_IEN_CALRDYIEN_DEFAULT CMU_IEN_CALRDY_DEFAULT
#define CMU_IEN_CALOFIEN CMU_IEN_CALOF
#define _CMU_IEN_CALOFIEN_SHIFT _CMU_IEN_CALOF_SHIFT
#define _CMU_IEN_CALOFIEN_MASK _CMU_IEN_CALOF_MASK
#define _CMU_IEN_CALOFIEN_DEFAULT _CMU_IEN_CALOF_DEFAULT
#define CMU_IEN_CALOFIEN_DEFAULT CMU_IEN_CALOF_DEFAULT
#define HFRCO_IF_RDYIF HFRCO_IF_RDY
#define _HFRCO_IF_RDYIF_SHIFT _HFRCO_IF_RDY_SHIFT
#define _HFRCO_IF_RDYIF_MASK _HFRCO_IF_RDY_MASK
#define _HFRCO_IF_RDYIF_DEFAULT _HFRCO_IF_RDY_DEFAULT
#define HFRCO_IF_RDYIF_DEFAULT HFRCO_IF_RDY_DEFAULT
#define HFRCO_IEN_RDYIEN HFRCO_IEN_RDY
#define _HFRCO_IEN_RDYIEN_SHIFT _HFRCO_IEN_RDY_SHIFT
#define _HFRCO_IEN_RDYIEN_MASK _HFRCO_IEN_RDY_MASK
#define _HFRCO_IEN_RDYIEN_DEFAULT _HFRCO_IEN_RDY_DEFAULT
#define HFRCO_IEN_RDYIEN_DEFAULT HFRCO_IEN_RDY_DEFAULT
#define LFRCO_IF_RDYIF LFRCO_IF_RDY
#define _LFRCO_IF_RDYIF_SHIFT _LFRCO_IF_RDY_SHIFT
#define _LFRCO_IF_RDYIF_MASK _LFRCO_IF_RDY_MASK
#define _LFRCO_IF_RDYIF_DEFAULT _LFRCO_IF_RDY_DEFAULT
#define LFRCO_IF_RDYIF_DEFAULT LFRCO_IF_RDY_DEFAULT
#define LFRCO_IF_POSEDGEIF LFRCO_IF_POSEDGE
#define _LFRCO_IF_POSEDGEIF_SHIFT _LFRCO_IF_POSEDGE_SHIFT
#define _LFRCO_IF_POSEDGEIF_MASK _LFRCO_IF_POSEDGE_MASK
#define _LFRCO_IF_POSEDGEIF_DEFAULT _LFRCO_IF_POSEDGE_DEFAULT
#define LFRCO_IF_POSEDGEIF_DEFAULT LFRCO_IF_POSEDGE_DEFAULT
#define LFRCO_IF_NEGEDGEIF LFRCO_IF_NEGEDGE
#define _LFRCO_IF_NEGEDGEIF_SHIFT _LFRCO_IF_NEGEDGE_SHIFT
#define _LFRCO_IF_NEGEDGEIF_MASK _LFRCO_IF_NEGEDGE_MASK
#define _LFRCO_IF_NEGEDGEIF_DEFAULT _LFRCO_IF_NEGEDGE_DEFAULT
#define LFRCO_IF_NEGEDGEIF_DEFAULT LFRCO_IF_NEGEDGE_DEFAULT
#define LFRCO_IF_TCDONEIF LFRCO_IF_TCDONE
#define _LFRCO_IF_TCDONEIF_SHIFT _LFRCO_IF_TCDONE_SHIFT
#define _LFRCO_IF_TCDONEIF_MASK _LFRCO_IF_TCDONE_MASK
#define _LFRCO_IF_TCDONEIF_DEFAULT _LFRCO_IF_TCDONE_DEFAULT
#define LFRCO_IF_TCDONEIF_DEFAULT LFRCO_IF_TCDONE_DEFAULT
#define LFRCO_IF_CALDONEIF LFRCO_IF_CALDONE
#define _LFRCO_IF_CALDONEIF_SHIFT _LFRCO_IF_CALDONE_SHIFT
#define _LFRCO_IF_CALDONEIF_MASK _LFRCO_IF_CALDONE_MASK
#define _LFRCO_IF_CALDONEIF_DEFAULT _LFRCO_IF_CALDONE_DEFAULT
#define LFRCO_IF_CALDONEIF_DEFAULT LFRCO_IF_CALDONE_DEFAULT
#define LFRCO_IF_TEMPCHANGEIF LFRCO_IF_TEMPCHANGE
#define _LFRCO_IF_TEMPCHANGEIF_SHIFT _LFRCO_IF_TEMPCHANGE_SHIFT
#define _LFRCO_IF_TEMPCHANGEIF_MASK _LFRCO_IF_TEMPCHANGE_MASK
#define _LFRCO_IF_TEMPCHANGEIF_DEFAULT _LFRCO_IF_TEMPCHANGE_DEFAULT
#define LFRCO_IF_TEMPCHANGEIF_DEFAULT LFRCO_IF_TEMPCHANGE_DEFAULT
#define LFRCO_IF_SCHEDERRIF LFRCO_IF_SCHEDERR
#define _LFRCO_IF_SCHEDERRIF_SHIFT _LFRCO_IF_SCHEDERR_SHIFT
#define _LFRCO_IF_SCHEDERRIF_MASK _LFRCO_IF_SCHEDERR_MASK
#define _LFRCO_IF_SCHEDERRIF_DEFAULT _LFRCO_IF_SCHEDERR_DEFAULT
#define LFRCO_IF_SCHEDERRIF_DEFAULT LFRCO_IF_SCHEDERR_DEFAULT
#define LFRCO_IF_TCOORIF LFRCO_IF_TCOOR
#define _LFRCO_IF_TCOORIF_SHIFT _LFRCO_IF_TCOOR_SHIFT
#define _LFRCO_IF_TCOORIF_MASK _LFRCO_IF_TCOOR_MASK
#define _LFRCO_IF_TCOORIF_DEFAULT _LFRCO_IF_TCOOR_DEFAULT
#define LFRCO_IF_TCOORIF_DEFAULT LFRCO_IF_TCOOR_DEFAULT
#define LFRCO_IF_CALOORIF LFRCO_IF_CALOOR
#define _LFRCO_IF_CALOORIF_SHIFT _LFRCO_IF_CALOOR_SHIFT
#define _LFRCO_IF_CALOORIF_MASK _LFRCO_IF_CALOOR_MASK
#define _LFRCO_IF_CALOORIF_DEFAULT _LFRCO_IF_CALOOR_DEFAULT
#define LFRCO_IF_CALOORIF_DEFAULT LFRCO_IF_CALOOR_DEFAULT
#define LFRCO_IEN_RDYIEN LFRCO_IEN_RDY
#define _LFRCO_IEN_RDYIEN_SHIFT _LFRCO_IEN_RDY_SHIFT
#define _LFRCO_IEN_RDYIEN_MASK _LFRCO_IEN_RDY_MASK
#define _LFRCO_IEN_RDYIEN_DEFAULT _LFRCO_IEN_RDY_DEFAULT
#define LFRCO_IEN_RDYIEN_DEFAULT LFRCO_IEN_RDY_DEFAULT
#define LFRCO_IEN_POSEDGEIEN LFRCO_IEN_POSEDGE
#define _LFRCO_IEN_POSEDGEIEN_SHIFT _LFRCO_IEN_POSEDGE_SHIFT
#define _LFRCO_IEN_POSEDGEIEN_MASK _LFRCO_IEN_POSEDGE_MASK
#define _LFRCO_IEN_POSEDGEIEN_DEFAULT _LFRCO_IEN_POSEDGE_DEFAULT
#define LFRCO_IEN_POSEDGEIEN_DEFAULT LFRCO_IEN_POSEDGE_DEFAULT
#define LFRCO_IEN_NEGEDGEIEN LFRCO_IEN_NEGEDGE
#define _LFRCO_IEN_NEGEDGEIEN_SHIFT _LFRCO_IEN_NEGEDGE_SHIFT
#define _LFRCO_IEN_NEGEDGEIEN_MASK _LFRCO_IEN_NEGEDGE_MASK
#define _LFRCO_IEN_NEGEDGEIEN_DEFAULT _LFRCO_IEN_NEGEDGE_DEFAULT
#define LFRCO_IEN_NEGEDGEIEN_DEFAULT LFRCO_IEN_NEGEDGE_DEFAULT
#define LFRCO_IEN_TCDONEIEN LFRCO_IEN_TCDONE
#define _LFRCO_IEN_TCDONEIEN_SHIFT _LFRCO_IEN_TCDONE_SHIFT
#define _LFRCO_IEN_TCDONEIEN_MASK _LFRCO_IEN_TCDONE_MASK
#define _LFRCO_IEN_TCDONEIEN_DEFAULT _LFRCO_IEN_TCDONE_DEFAULT
#define LFRCO_IEN_TCDONEIEN_DEFAULT LFRCO_IEN_TCDONE_DEFAULT
#define LFRCO_IEN_CALDONEIEN LFRCO_IEN_CALDONE
#define _LFRCO_IEN_CALDONEIEN_SHIFT _LFRCO_IEN_CALDONE_SHIFT
#define _LFRCO_IEN_CALDONEIEN_MASK _LFRCO_IEN_CALDONE_MASK
#define _LFRCO_IEN_CALDONEIEN_DEFAULT _LFRCO_IEN_CALDONE_DEFAULT
#define LFRCO_IEN_CALDONEIEN_DEFAULT LFRCO_IEN_CALDONE_DEFAULT
#define LFRCO_IEN_TEMPCHANGEIEN LFRCO_IEN_TEMPCHANGE
#define _LFRCO_IEN_TEMPCHANGEIEN_SHIFT _LFRCO_IEN_TEMPCHANGE_SHIFT
#define _LFRCO_IEN_TEMPCHANGEIEN_MASK _LFRCO_IEN_TEMPCHANGE_MASK
#define _LFRCO_IEN_TEMPCHANGEIEN_DEFAULT _LFRCO_IEN_TEMPCHANGE_DEFAULT
#define LFRCO_IEN_TEMPCHANGEIEN_DEFAULT LFRCO_IEN_TEMPCHANGE_DEFAULT
#define LFRCO_IEN_SCHEDERRIEN LFRCO_IEN_SCHEDERR
#define _LFRCO_IEN_SCHEDERRIEN_SHIFT _LFRCO_IEN_SCHEDERR_SHIFT
#define _LFRCO_IEN_SCHEDERRIEN_MASK _LFRCO_IEN_SCHEDERR_MASK
#define _LFRCO_IEN_SCHEDERRIEN_DEFAULT _LFRCO_IEN_SCHEDERR_DEFAULT
#define LFRCO_IEN_SCHEDERRIEN_DEFAULT LFRCO_IEN_SCHEDERR_DEFAULT
#define LFRCO_IEN_TCOORIEN LFRCO_IEN_TCOOR
#define _LFRCO_IEN_TCOORIEN_SHIFT _LFRCO_IEN_TCOOR_SHIFT
#define _LFRCO_IEN_TCOORIEN_MASK _LFRCO_IEN_TCOOR_MASK
#define _LFRCO_IEN_TCOORIEN_DEFAULT _LFRCO_IEN_TCOOR_DEFAULT
#define LFRCO_IEN_TCOORIEN_DEFAULT LFRCO_IEN_TCOOR_DEFAULT
#define LFRCO_IEN_CALOORIEN LFRCO_IEN_CALOOR
#define _LFRCO_IEN_CALOORIEN_SHIFT _LFRCO_IEN_CALOOR_SHIFT
#define _LFRCO_IEN_CALOORIEN_MASK _LFRCO_IEN_CALOOR_MASK
#define _LFRCO_IEN_CALOORIEN_DEFAULT _LFRCO_IEN_CALOOR_DEFAULT
#define LFRCO_IEN_CALOORIEN_DEFAULT LFRCO_IEN_CALOOR_DEFAULT
#endif /* _SILICON_LABS_32B_SERIES_2_CONFIG_2 */
#endif

View File

@@ -0,0 +1,36 @@
/***************************************************************************//**
* @file
* @brief General purpose utilities.
*******************************************************************************
* # License
* <b>Copyright 2018 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* 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.
*
******************************************************************************/
#ifndef EM_COMMON_H
#define EM_COMMON_H
#include "em_device.h"
#include "sl_common.h"
#endif /* EM_COMMON_H */

View File

@@ -0,0 +1,174 @@
/***************************************************************************//**
* @file
* @brief Core interrupt handling API (Device Specific)
*******************************************************************************
* # License
* <b>Copyright 2018 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* 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.
*
******************************************************************************/
#ifndef EM_CORE_H
#define EM_CORE_H
#include "em_device.h"
#include "em_core_generic.h"
#include "sl_common.h"
/***************************************************************************//**
* @addtogroup core
* @{
******************************************************************************/
/*******************************************************************************
******************************* DEFINES ***********************************
******************************************************************************/
/** Number of words in a NVIC mask set. */
#define CORE_NVIC_REG_WORDS ((EXT_IRQ_COUNT + 31) / 32)
/** Number of entries in a default interrupt vector table. */
#define CORE_DEFAULT_VECTOR_TABLE_ENTRIES (EXT_IRQ_COUNT + 16)
/** Highest priority for core interrupt. */
#define CORE_INTERRUPT_HIGHEST_PRIORITY 0
/** Default priority for core interrupt. */
#define CORE_INTERRUPT_DEFAULT_PRIORITY 5
/** Lowest priority for core interrupt. */
#define CORE_INTERRUPT_LOWEST_PRIORITY 7
// Compile time sanity check.
#if (CORE_NVIC_REG_WORDS > 3)
#error "em_core: Unexpected NVIC external interrupt count."
#endif
#ifdef __cplusplus
extern "C" {
#endif
/*******************************************************************************
************************ MACRO API ***************************************
******************************************************************************/
//
// NVIC mask section macro API.
//
/** Allocate storage for NVIC interrupt masks for use by
* CORE_ENTER/EXIT_NVIC() macros. */
#define CORE_DECLARE_NVIC_STATE CORE_nvicMask_t nvicState
/** Allocate storage for NVIC interrupt masks.
* @param[in] x
* The storage variable name to use.*/
#define CORE_DECLARE_NVIC_MASK(x) CORE_nvicMask_t x
/** Allocate storage for and zero initialize NVIC interrupt mask.
* @param[in] x
* The storage variable name to use.*/
#define CORE_DECLARE_NVIC_ZEROMASK(x) CORE_nvicMask_t x = { { 0 } }
/** NVIC mask style interrupt disable.
* @param[in] mask
* Mask specifying which NVIC interrupts to disable. */
#define CORE_NVIC_DISABLE(mask) CORE_NvicDisableMask(mask)
/** NVIC mask style interrupt enable.
* @param[in] mask
* Mask specifying which NVIC interrupts to enable. */
#define CORE_NVIC_ENABLE(mask) CORE_NvicEnableMask(mask)
/** Convenience macro for implementing a NVIC mask section.
* @param[in] mask
* Mask specifying which NVIC interrupts to disable within the section.
* @param[in] yourcode
* The code for the section. */
#define CORE_NVIC_SECTION(mask, yourcode) \
{ \
CORE_DECLARE_NVIC_STATE; \
CORE_ENTER_NVIC(mask); \
{ \
yourcode \
} \
CORE_EXIT_NVIC(); \
}
/** Enter NVIC mask section. Assumes that a @ref CORE_DECLARE_NVIC_STATE exist
* in scope.
* @param[in] disable
* Mask specifying which NVIC interrupts to disable within the section. */
#define CORE_ENTER_NVIC(disable) CORE_EnterNvicMask(&nvicState, disable)
/** Exit NVIC mask section. Assumes that a @ref CORE_DECLARE_NVIC_STATE exist
* in scope. */
#define CORE_EXIT_NVIC() CORE_NvicEnableMask(&nvicState)
/** NVIC maks style yield.
* @param[in] enable
* Mask specifying which NVIC interrupts to briefly enable. */
#define CORE_YIELD_NVIC(enable) CORE_YieldNvicMask(enable)
/*******************************************************************************
************************* TYPEDEFS ****************************************
******************************************************************************/
/** Storage for NVIC interrupt masks. */
typedef struct {
uint32_t a[CORE_NVIC_REG_WORDS]; /*!< Array of NVIC mask words. */
} CORE_nvicMask_t;
/*******************************************************************************
***************************** PROTOTYPES **********************************
******************************************************************************/
bool CORE_IrqIsBlocked(IRQn_Type irqN) SL_DEPRECATED_API_SDK_2024_6;
void CORE_GetNvicEnabledMask(CORE_nvicMask_t *mask) SL_DEPRECATED_API_SDK_2024_6;
bool CORE_GetNvicMaskDisableState(const CORE_nvicMask_t *mask) SL_DEPRECATED_API_SDK_2024_6;
void CORE_EnterNvicMask(CORE_nvicMask_t *nvicState,
const CORE_nvicMask_t *disable) SL_DEPRECATED_API_SDK_2024_6;
void CORE_NvicDisableMask(const CORE_nvicMask_t *disable) SL_DEPRECATED_API_SDK_2024_6;
void CORE_NvicEnableMask(const CORE_nvicMask_t *enable) SL_DEPRECATED_API_SDK_2024_6;
void CORE_YieldNvicMask(const CORE_nvicMask_t *enable) SL_DEPRECATED_API_SDK_2024_6;
void CORE_NvicMaskSetIRQ(IRQn_Type irqN, CORE_nvicMask_t *mask) SL_DEPRECATED_API_SDK_2024_6;
void CORE_NvicMaskClearIRQ(IRQn_Type irqN, CORE_nvicMask_t *mask) SL_DEPRECATED_API_SDK_2024_6;
bool CORE_NvicIRQDisabled(IRQn_Type irqN) SL_DEPRECATED_API_SDK_2024_6;
void *CORE_GetNvicRamTableHandler(IRQn_Type irqN) SL_DEPRECATED_API_SDK_2024_6;
void CORE_SetNvicRamTableHandler(IRQn_Type irqN, void *handler) SL_DEPRECATED_API_SDK_2024_6;
void CORE_InitNvicVectorTable(uint32_t *sourceTable,
uint32_t sourceSize,
uint32_t *targetTable,
uint32_t targetSize,
void *defaultHandler,
bool overwriteActive);
#ifdef __cplusplus
}
#endif
/** @} (end addtogroup core) */
#endif /* EM_CORE_H */

View File

@@ -0,0 +1,36 @@
/***************************************************************************//**
* @file
* @brief Core interrupt handling API (Generic)
*******************************************************************************
* # License
* <b>Copyright 2023 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* 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.
*
******************************************************************************/
#ifndef EM_CORE_GENERIC_H
#define EM_CORE_GENERIC_H
#include "sl_core.h"
#endif /* EM_CORE_GENERIC_H */

View File

@@ -0,0 +1,130 @@
/***************************************************************************//**
* @file
* @brief Debug (DBG) API
*******************************************************************************
* # License
* <b>Copyright 2018 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* 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.
*
******************************************************************************/
#ifndef EM_DBG_H
#define EM_DBG_H
#include <stdbool.h>
#include "em_device.h"
#if defined(CoreDebug_DHCSR_C_DEBUGEN_Msk)
#ifdef __cplusplus
extern "C" {
#endif
/***************************************************************************//**
* @addtogroup dbg
* @{
******************************************************************************/
/*******************************************************************************
******************************** ENUMS ************************************
******************************************************************************/
/** Lock modes */
typedef enum {
dbgLockModeAllowErase = 1UL, /**< Lock debug access. */
#if !defined(_SILICON_LABS_32B_SERIES_0)
dbgLockModePermanent = 2UL /**< Lock debug access permanently. */
#endif
} DBG_LockMode_TypeDef;
/*******************************************************************************
***************************** PROTOTYPES **********************************
******************************************************************************/
#if defined(GPIO_ROUTE_SWCLKPEN) \
|| defined(GPIO_ROUTEPEN_SWCLKTCKPEN) \
|| defined(GPIO_DBGROUTEPEN_SWCLKTCKPEN)
/***************************************************************************//**
* @brief
* Check if a debugger is connected (and debug session activated).
*
* @details
* Used to make run-time decisions depending on whether or not a debug session
* has been active since last reset, i.e., using a debug probe or similar. In
* some cases, special handling is required in that scenario.
*
* @return
* True if a debug session is active since last reset, otherwise false.
******************************************************************************/
__STATIC_INLINE bool DBG_Connected(void)
{
return (CoreDebug->DHCSR & CoreDebug_DHCSR_C_DEBUGEN_Msk) ? true : false;
}
#endif
#if defined(GPIO_ROUTE_SWOPEN) \
|| defined(GPIO_ROUTEPEN_SWVPEN) \
|| defined(GPIO_TRACEROUTEPEN_SWVPEN)
void DBG_SWOEnable(unsigned int location);
#endif
#if defined (EMU_CTRL_EM2DBGEN)
/***************************************************************************//**
* @brief
* Enable or disable debug support while in EM2 mode.
*
* @warning
* Disabling debug support in EM2 will reduce current consumption with 1-2 uA,
* but some debuggers will have problems regaining control over a device which
* is in EM2 and has debug support disabled.
*
* To remedy this, set the WSTK switch next to the battery holder to USB
* (powers down the EFR). Execute Simplicity Commander with command line
* parameters:
* "./commander.exe device recover"
* and then immediately move the switch to the AEM position. An additional
* "./commander.exe device masserase"
* command completes the recovery procedure.
*
* @param[in] enable
* Boolean true enables EM2 debug support, false disables.
******************************************************************************/
__STATIC_INLINE void DBG_EM2DebugEnable(bool enable)
{
if (enable) {
EMU->CTRL_SET = EMU_CTRL_EM2DBGEN;
} else {
EMU->CTRL_CLR = EMU_CTRL_EM2DBGEN;
}
}
#endif
/** @} (end addtogroup dbg) */
#ifdef __cplusplus
}
#endif
#endif /* defined( CoreDebug_DHCSR_C_DEBUGEN_Msk ) */
#endif /* EM_DBG_H */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,218 @@
/***************************************************************************//**
* @file
* @brief EUSART Compatibility Header
*******************************************************************************
* # License
* <b>Copyright 2020 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* 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.
*
******************************************************************************/
#ifndef EM_EUSART_COMPAT_H
#define EM_EUSART_COMPAT_H
#if defined(_SILICON_LABS_32B_SERIES_2_CONFIG_2)
#define EUSART_IF_TXCIF EUSART_IF_TXC
#define _EUSART_IF_TXCIF_SHIFT _EUSART_IF_TXC_SHIFT
#define _EUSART_IF_TXCIF_MASK _EUSART_IF_TXC_MASK
#define _EUSART_IF_TXCIF_DEFAULT _EUSART_IF_TXC_DEFAULT
#define EUSART_IF_TXCIF_DEFAULT EUSART_IF_TXC_DEFAULT
#define EUSART_IF_TXFLIF EUSART_IF_TXFL
#define _EUSART_IF_TXFLIF_SHIFT _EUSART_IF_TXFL_SHIFT
#define _EUSART_IF_TXFLIF_MASK _EUSART_IF_TXFL_MASK
#define _EUSART_IF_TXFLIF_DEFAULT _EUSART_IF_TXFL_DEFAULT
#define EUSART_IF_TXFLIF_DEFAULT EUSART_IF_TXFL_DEFAULT
#define EUSART_IF_RXFLIF EUSART_IF_RXFL
#define _EUSART_IF_RXFLIF_SHIFT _EUSART_IF_RXFL_SHIFT
#define _EUSART_IF_RXFLIF_MASK _EUSART_IF_RXFL_MASK
#define _EUSART_IF_RXFLIF_DEFAULT _EUSART_IF_RXFL_DEFAULT
#define EUSART_IF_RXFLIF_DEFAULT EUSART_IF_RXFL_DEFAULT
#define EUSART_IF_RXFULLIF EUSART_IF_RXFULL
#define _EUSART_IF_RXFULLIF_SHIFT _EUSART_IF_RXFULL_SHIFT
#define _EUSART_IF_RXFULLIF_MASK _EUSART_IF_RXFULL_MASK
#define _EUSART_IF_RXFULLIF_DEFAULT _EUSART_IF_RXFULL_DEFAULT
#define EUSART_IF_RXFULLIF_DEFAULT EUSART_IF_RXFULL_DEFAULT
#define EUSART_IF_RXOFIF EUSART_IF_RXOF
#define _EUSART_IF_RXOFIF_SHIFT _EUSART_IF_RXOF_SHIFT
#define _EUSART_IF_RXOFIF_MASK _EUSART_IF_RXOF_MASK
#define _EUSART_IF_RXOFIF_DEFAULT _EUSART_IF_RXOF_DEFAULT
#define EUSART_IF_RXOFIF_DEFAULT EUSART_IF_RXOF_DEFAULT
#define EUSART_IF_RXUFIF EUSART_IF_RXUF
#define _EUSART_IF_RXUFIF_SHIFT _EUSART_IF_RXUF_SHIFT
#define _EUSART_IF_RXUFIF_MASK _EUSART_IF_RXUF_MASK
#define _EUSART_IF_RXUFIF_DEFAULT _EUSART_IF_RXUF_DEFAULT
#define EUSART_IF_RXUFIF_DEFAULT EUSART_IF_RXUF_DEFAULT
#define EUSART_IF_TXOFIF EUSART_IF_TXOF
#define _EUSART_IF_TXOFIF_SHIFT _EUSART_IF_TXOF_SHIFT
#define _EUSART_IF_TXOFIF_MASK _EUSART_IF_TXOF_MASK
#define _EUSART_IF_TXOFIF_DEFAULT _EUSART_IF_TXOF_DEFAULT
#define EUSART_IF_TXOFIF_DEFAULT EUSART_IF_TXOF_DEFAULT
#define EUSART_IF_PERRIF EUSART_IF_PERR
#define _EUSART_IF_PERRIF_SHIFT _EUSART_IF_PERR_SHIFT
#define _EUSART_IF_PERRIF_MASK _EUSART_IF_PERR_MASK
#define _EUSART_IF_PERRIF_DEFAULT _EUSART_IF_PERR_DEFAULT
#define EUSART_IF_PERRIF_DEFAULT EUSART_IF_PERR_DEFAULT
#define EUSART_IF_FERRIF EUSART_IF_FERR
#define _EUSART_IF_FERRIF_SHIFT _EUSART_IF_FERR_SHIFT
#define _EUSART_IF_FERRIF_MASK _EUSART_IF_FERR_MASK
#define _EUSART_IF_FERRIF_DEFAULT _EUSART_IF_FERR_DEFAULT
#define EUSART_IF_FERRIF_DEFAULT EUSART_IF_FERR_DEFAULT
#define EUSART_IF_MPAFIF EUSART_IF_MPAF
#define _EUSART_IF_MPAFIF_SHIFT _EUSART_IF_MPAF_SHIFT
#define _EUSART_IF_MPAFIF_MASK _EUSART_IF_MPAF_MASK
#define _EUSART_IF_MPAFIF_DEFAULT _EUSART_IF_MPAF_DEFAULT
#define EUSART_IF_MPAFIF_DEFAULT EUSART_IF_MPAF_DEFAULT
#define EUSART_IF_CCFIF EUSART_IF_CCF
#define _EUSART_IF_CCFIF_SHIFT _EUSART_IF_CCF_SHIFT
#define _EUSART_IF_CCFIF_MASK _EUSART_IF_CCF_MASK
#define _EUSART_IF_CCFIF_DEFAULT _EUSART_IF_CCF_DEFAULT
#define EUSART_IF_CCFIF_DEFAULT EUSART_IF_CCF_DEFAULT
#define EUSART_IF_TXIDLEIF EUSART_IF_TXIDLE
#define _EUSART_IF_TXIDLEIF_SHIFT _EUSART_IF_TXIDLE_SHIFT
#define _EUSART_IF_TXIDLEIF_MASK _EUSART_IF_TXIDLE_MASK
#define _EUSART_IF_TXIDLEIF_DEFAULT _EUSART_IF_TXIDLE_DEFAULT
#define EUSART_IF_TXIDLEIF_DEFAULT EUSART_IF_TXIDLE_DEFAULT
#define EUSART_IF_STARTFIF EUSART_IF_STARTF
#define _EUSART_IF_STARTFIF_SHIFT _EUSART_IF_STARTF_SHIFT
#define _EUSART_IF_STARTFIF_MASK _EUSART_IF_STARTF_MASK
#define _EUSART_IF_STARTFIF_DEFAULT _EUSART_IF_STARTF_DEFAULT
#define EUSART_IF_STARTFIF_DEFAULT EUSART_IF_STARTF_DEFAULT
#define EUSART_IF_SIGFIF EUSART_IF_SIGF
#define _EUSART_IF_SIGFIF_SHIFT _EUSART_IF_SIGF_SHIFT
#define _EUSART_IF_SIGFIF_MASK _EUSART_IF_SIGF_MASK
#define _EUSART_IF_SIGFIF_DEFAULT _EUSART_IF_SIGF_DEFAULT
#define EUSART_IF_SIGFIF_DEFAULT EUSART_IF_SIGF_DEFAULT
#define EUSART_IF_AUTOBAUDDONEIF EUSART_IF_AUTOBAUDDONE
#define _EUSART_IF_AUTOBAUDDONEIF_SHIFT _EUSART_IF_AUTOBAUDDONE_SHIFT
#define _EUSART_IF_AUTOBAUDDONEIF_MASK _EUSART_IF_AUTOBAUDDONE_MASK
#define _EUSART_IF_AUTOBAUDDONEIF_DEFAULT _EUSART_IF_AUTOBAUDDONE_DEFAULT
#define EUSART_IF_AUTOBAUDDONEIF_DEFAULT EUSART_IF_AUTOBAUDDONE_DEFAULT
#define EUSART_IEN_TXCIEN EUSART_IEN_TXC
#define _EUSART_IEN_TXCIEN_SHIFT _EUSART_IEN_TXC_SHIFT
#define _EUSART_IEN_TXCIEN_MASK _EUSART_IEN_TXC_MASK
#define _EUSART_IEN_TXCIEN_DEFAULT _EUSART_IEN_TXC_DEFAULT
#define EUSART_IEN_TXCIEN_DEFAULT EUSART_IEN_TXC_DEFAULT
#define EUSART_IEN_TXFLIEN EUSART_IEN_TXFL
#define _EUSART_IEN_TXFLIEN_SHIFT _EUSART_IEN_TXFL_SHIFT
#define _EUSART_IEN_TXFLIEN_MASK _EUSART_IEN_TXFL_MASK
#define _EUSART_IEN_TXFLIEN_DEFAULT _EUSART_IEN_TXFL_DEFAULT
#define EUSART_IEN_TXFLIEN_DEFAULT EUSART_IEN_TXFL_DEFAULT
#define EUSART_IEN_RXFLIEN EUSART_IEN_RXFL
#define _EUSART_IEN_RXFLIEN_SHIFT _EUSART_IEN_RXFL_SHIFT
#define _EUSART_IEN_RXFLIEN_MASK _EUSART_IEN_RXFL_MASK
#define _EUSART_IEN_RXFLIEN_DEFAULT _EUSART_IEN_RXFL_DEFAULT
#define EUSART_IEN_RXFLIEN_DEFAULT EUSART_IEN_RXFL_DEFAULT
#define EUSART_IEN_RXFULLIEN EUSART_IEN_RXFULL
#define _EUSART_IEN_RXFULLIEN_SHIFT _EUSART_IEN_RXFULL_SHIFT
#define _EUSART_IEN_RXFULLIEN_MASK _EUSART_IEN_RXFULL_MASK
#define _EUSART_IEN_RXFULLIEN_DEFAULT _EUSART_IEN_RXFULL_DEFAULT
#define EUSART_IEN_RXFULLIEN_DEFAULT EUSART_IEN_RXFULL_DEFAULT
#define EUSART_IEN_RXOFIEN EUSART_IEN_RXOF
#define _EUSART_IEN_RXOFIEN_SHIFT _EUSART_IEN_RXOF_SHIFT
#define _EUSART_IEN_RXOFIEN_MASK _EUSART_IEN_RXOF_MASK
#define _EUSART_IEN_RXOFIEN_DEFAULT _EUSART_IEN_RXOF_DEFAULT
#define EUSART_IEN_RXOFIEN_DEFAULT EUSART_IEN_RXOF_DEFAULT
#define EUSART_IEN_RXUFIEN EUSART_IEN_RXUF
#define _EUSART_IEN_RXUFIEN_SHIFT _EUSART_IEN_RXUF_SHIFT
#define _EUSART_IEN_RXUFIEN_MASK _EUSART_IEN_RXUF_MASK
#define _EUSART_IEN_RXUFIEN_DEFAULT _EUSART_IEN_RXUF_DEFAULT
#define EUSART_IEN_RXUFIEN_DEFAULT EUSART_IEN_RXUF_DEFAULT
#define EUSART_IEN_TXOFIEN EUSART_IEN_TXOF
#define _EUSART_IEN_TXOFIEN_SHIFT _EUSART_IEN_TXOF_SHIFT
#define _EUSART_IEN_TXOFIEN_MASK _EUSART_IEN_TXOF_MASK
#define _EUSART_IEN_TXOFIEN_DEFAULT _EUSART_IEN_TXOF_DEFAULT
#define EUSART_IEN_TXOFIEN_DEFAULT EUSART_IEN_TXOF_DEFAULT
#define EUSART_IEN_PERRIEN EUSART_IEN_PERR
#define _EUSART_IEN_PERRIEN_SHIFT _EUSART_IEN_PERR_SHIFT
#define _EUSART_IEN_PERRIEN_MASK _EUSART_IEN_PERR_MASK
#define _EUSART_IEN_PERRIEN_DEFAULT _EUSART_IEN_PERR_DEFAULT
#define EUSART_IEN_PERRIEN_DEFAULT EUSART_IEN_PERR_DEFAULT
#define EUSART_IEN_FERRIEN EUSART_IEN_FERR
#define _EUSART_IEN_FERRIEN_SHIFT _EUSART_IEN_FERR_SHIFT
#define _EUSART_IEN_FERRIEN_MASK _EUSART_IEN_FERR_MASK
#define _EUSART_IEN_FERRIEN_DEFAULT _EUSART_IEN_FERR_DEFAULT
#define EUSART_IEN_FERRIEN_DEFAULT EUSART_IEN_FERR_DEFAULT
#define EUSART_IEN_MPAFIEN EUSART_IEN_MPAF
#define _EUSART_IEN_MPAFIEN_SHIFT _EUSART_IEN_MPAF_SHIFT
#define _EUSART_IEN_MPAFIEN_MASK _EUSART_IEN_MPAF_MASK
#define _EUSART_IEN_MPAFIEN_DEFAULT _EUSART_IEN_MPAF_DEFAULT
#define EUSART_IEN_MPAFIEN_DEFAULT EUSART_IEN_MPAF_DEFAULT
#define EUSART_IEN_CCFIEN EUSART_IEN_CCF
#define _EUSART_IEN_CCFIEN_SHIFT _EUSART_IEN_CCF_SHIFT
#define _EUSART_IEN_CCFIEN_MASK _EUSART_IEN_CCF_MASK
#define _EUSART_IEN_CCFIEN_DEFAULT _EUSART_IEN_CCF_DEFAULT
#define EUSART_IEN_CCFIEN_DEFAULT EUSART_IEN_CCF_DEFAULT
#define EUSART_IEN_TXIDLEIEN EUSART_IEN_TXIDLE
#define _EUSART_IEN_TXIDLEIEN_SHIFT _EUSART_IEN_TXIDLE_SHIFT
#define _EUSART_IEN_TXIDLEIEN_MASK _EUSART_IEN_TXIDLE_MASK
#define _EUSART_IEN_TXIDLEIEN_DEFAULT _EUSART_IEN_TXIDLE_DEFAULT
#define EUSART_IEN_TXIDLEIEN_DEFAULT EUSART_IEN_TXIDLE_DEFAULT
#define EUSART_IEN_STARTFIEN EUSART_IEN_STARTF
#define _EUSART_IEN_STARTFIEN_SHIFT _EUSART_IEN_STARTF_SHIFT
#define _EUSART_IEN_STARTFIEN_MASK _EUSART_IEN_STARTF_MASK
#define _EUSART_IEN_STARTFIEN_DEFAULT _EUSART_IEN_STARTF_DEFAULT
#define EUSART_IEN_STARTFIEN_DEFAULT EUSART_IEN_STARTF_DEFAULT
#define EUSART_IEN_SIGFIEN EUSART_IEN_SIGF
#define _EUSART_IEN_SIGFIEN_SHIFT _EUSART_IEN_SIGF_SHIFT
#define _EUSART_IEN_SIGFIEN_MASK _EUSART_IEN_SIGF_MASK
#define _EUSART_IEN_SIGFIEN_DEFAULT _EUSART_IEN_SIGF_DEFAULT
#define EUSART_IEN_SIGFIEN_DEFAULT EUSART_IEN_SIGF_DEFAULT
#define EUSART_IEN_AUTOBAUDDONEIEN EUSART_IEN_AUTOBAUDDONE
#define _EUSART_IEN_AUTOBAUDDONEIEN_SHIFT _EUSART_IEN_AUTOBAUDDONE_SHIFT
#define _EUSART_IEN_AUTOBAUDDONEIEN_MASK _EUSART_IEN_AUTOBAUDDONE_MASK
#define _EUSART_IEN_AUTOBAUDDONEIEN_DEFAULT _EUSART_IEN_AUTOBAUDDONE_DEFAULT
#define EUSART_IEN_AUTOBAUDDONEIEN_DEFAULT EUSART_IEN_AUTOBAUDDONE_DEFAULT
#endif // _SILICON_LABS_32B_SERIES_2_CONFIG_2
#endif

View File

@@ -0,0 +1,346 @@
/***************************************************************************//**
* @file
* @brief General Purpose Cyclic Redundancy Check (GPCRC) API.
*******************************************************************************
* # License
* <b>Copyright 2018 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* 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.
*
******************************************************************************/
#ifndef EM_GPCRC_H
#define EM_GPCRC_H
#include "em_bus.h"
#include "em_device.h"
#if defined(GPCRC_PRESENT) && (GPCRC_COUNT > 0)
#include <stdint.h>
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
/***************************************************************************//**
* @addtogroup gpcrc GPCRC - General Purpose CRC
* @brief General Purpose Cyclic Redundancy Check (GPCRC) API
*
* @details
* The GPCRC API functions provide full support for the GPCRC peripheral.
*
* The GPCRC module is a peripheral that implements a Cyclic Redundancy Check
* (CRC) function. It supports a fixed 32-bit polynomial and a user
* configurable 16-bit polynomial. The fixed 32-bit polynomial is the commonly
* used IEEE 802.3 polynomial 0x04C11DB7.
*
* When using a 16-bit polynomial it is up to the user to choose a polynomial
* that fits the application. Commonly used 16-bit polynomials are 0x1021
* (CCITT-16), 0x3D65 (IEC16-MBus), and 0x8005 (ZigBee, 802.15.4, and USB).
* See this link for other polynomials:
* https://en.wikipedia.org/wiki/Cyclic_redundancy_check
*
* Before a CRC calculation can begin, call the
* @ref GPCRC_Start function. This function will reset CRC calculation
* by copying the configured initialization value over to the CRC data register.
*
* There are two ways of sending input data to the GPCRC. Either write
* the input data into the input data register using input functions
* @ref GPCRC_InputU32, @ref GPCRC_InputU16 and @ref GPCRC_InputU8, or the
* user can configure @ref ldma to transfer data directly to one of the GPCRC
* input data registers.
*
* <b> Examples of GPCRC usage: </b>
*
* A CRC-32 Calculation:
*
* @include em_gpcrc_crc32.c
*
* A CRC-16 Calculation:
*
* @include em_gpcrc_crc16.c
*
* A CRC-CCITT calculation:
*
* @include em_gpcrc_ccit.c
*
* @{
******************************************************************************/
/*******************************************************************************
******************************* STRUCTS ***********************************
******************************************************************************/
/** CRC initialization structure. */
typedef struct {
/**
* CRC polynomial value. GPCRC supports either a fixed 32-bit polynomial
* or a user-configurable 16 bit polynomial. The fixed 32-bit polynomial
* is the one used in IEEE 802.3, which has the value 0x04C11DB7. To use the
* 32-bit fixed polynomial, assign 0x04C11DB7 to the crcPoly field.
* To use a 16-bit polynomial, assign a value to crcPoly where the upper 16
* bits are zero.
*
* The polynomial should be written in normal bit order. For instance,
* to use the CRC-16 polynomial X^16 + X^15 + X^2 + 1, first convert
* it to hex representation and remove the highest order term
* of the polynomial. This will give 0x8005 as the value to write into
* crcPoly.
*/
uint32_t crcPoly;
/**
* CRC initialization value. This value is assigned to the GPCRC_INIT register.
* The initValue is loaded into the data register when calling the
* @ref GPCRC_Start function or when one of the data registers are read
* while @ref autoInit is enabled.
*/
uint32_t initValue;
/**
* Reverse byte order. This has an effect when sending a 32-bit word or
* 16-bit half word input to the CRC calculation. When set to true, the input
* bytes are reversed before entering the CRC calculation. When set to
* false, the input bytes stay in the same order.
*/
bool reverseByteOrder;
/**
* Reverse bits within each input byte. This setting enables or disables byte
* level bit reversal. When byte-level bit reversal is enabled, then each byte
* of input data will be reversed before entering CRC calculation.
*/
bool reverseBits;
/**
* Enable/disable byte mode. When byte mode is enabled, then all input
* is treated as single byte input even though the input is a 32-bit word
* or a 16-bit half word. Only the least significant byte of the data-word
* will be used for CRC calculation for all writes.
*/
bool enableByteMode;
/**
* Enable automatic initialization by re-seeding the CRC result based on
* the init value after reading one of the CRC data registers.
*/
bool autoInit;
/** Enable/disable GPCRC when initialization is completed. */
bool enable;
} GPCRC_Init_TypeDef;
/** Default configuration for GPCRC_Init_TypeDef structure. */
#define GPCRC_INIT_DEFAULT \
{ \
0x04C11DB7UL, /* CRC32 Polynomial value. */ \
0x00000000UL, /* Initialization value. */ \
false, /* Byte order is normal. */ \
false, /* Bit order is not reversed on output. */ \
false, /* Disable byte mode. */ \
false, /* Disable automatic initialization on data read. */ \
true, /* Enable GPCRC. */ \
}
/*******************************************************************************
****************************** PROTOTYPES *********************************
******************************************************************************/
void GPCRC_Init(GPCRC_TypeDef * gpcrc, const GPCRC_Init_TypeDef * init);
void GPCRC_Reset(GPCRC_TypeDef * gpcrc);
/***************************************************************************//**
* @brief
* Enable/disable GPCRC.
*
* @param[in] gpcrc
* Pointer to GPCRC peripheral register block.
*
* @param[in] enable
* True to enable GPCRC, false to disable.
******************************************************************************/
__STATIC_INLINE void GPCRC_Enable(GPCRC_TypeDef * gpcrc, bool enable)
{
#if defined(GPCRC_EN_EN)
BUS_RegBitWrite(&gpcrc->EN, _GPCRC_EN_EN_SHIFT, enable);
#else
BUS_RegBitWrite(&gpcrc->CTRL, _GPCRC_CTRL_EN_SHIFT, enable);
#endif
}
/***************************************************************************//**
* @brief
* Issue a command to initialize the CRC calculation.
*
* @details
* Issues the command INIT in GPCRC_CMD that initializes the
* CRC calculation by writing the initial values to the DATA register.
*
* @param[in] gpcrc
* Pointer to GPCRC peripheral register block.
******************************************************************************/
__STATIC_INLINE void GPCRC_Start(GPCRC_TypeDef * gpcrc)
{
gpcrc->CMD = GPCRC_CMD_INIT;
}
/***************************************************************************//**
* @brief
* Set the initialization value of the CRC.
*
* @param [in] initValue
* Value to use to initialize a CRC calculation. This value is moved into
* the data register when calling @ref GPCRC_Start
*
* @param[in] gpcrc
* Pointer to GPCRC peripheral register block.
******************************************************************************/
__STATIC_INLINE void GPCRC_InitValueSet(GPCRC_TypeDef * gpcrc, uint32_t initValue)
{
gpcrc->INIT = initValue;
}
/***************************************************************************//**
* @brief
* Write a 32-bit value to the input data register of the CRC.
*
* @details
* Use this function to write a 32-bit input data to the CRC. CRC
* calculation is based on the provided input data using the configured
* CRC polynomial.
*
* @param[in] gpcrc
* Pointer to GPCRC peripheral register block.
*
* @param[in] data
* Data to be written to the input data register.
******************************************************************************/
__STATIC_INLINE void GPCRC_InputU32(GPCRC_TypeDef * gpcrc, uint32_t data)
{
gpcrc->INPUTDATA = data;
}
/***************************************************************************//**
* @brief
* Write a 16-bit value to the input data register of the CRC.
*
* @details
* Use this function to write a 16 bit input data to the CRC. CRC
* calculation is based on the provided input data using the configured
* CRC polynomial.
*
* @param[in] gpcrc
* Pointer to GPCRC peripheral register block.
*
* @param[in] data
* Data to be written to the input data register.
******************************************************************************/
__STATIC_INLINE void GPCRC_InputU16(GPCRC_TypeDef * gpcrc, uint16_t data)
{
gpcrc->INPUTDATAHWORD = data;
}
/***************************************************************************//**
* @brief
* Write an 8-bit value to the CRC input data register.
*
* @details
* Use this function to write an 8-bit input data to the CRC. CRC
* calculation is based on the provided input data using the configured
* CRC polynomial.
*
* @param[in] gpcrc
* Pointer to GPCRC peripheral register block.
*
* @param[in] data
* Data to be written to the input data register.
******************************************************************************/
__STATIC_INLINE void GPCRC_InputU8(GPCRC_TypeDef * gpcrc, uint8_t data)
{
gpcrc->INPUTDATABYTE = data;
}
/***************************************************************************//**
* @brief
* Read the CRC data register.
*
* @details
* Use this function to read the calculated CRC value.
*
* @param[in] gpcrc
* Pointer to GPCRC peripheral register block.
*
* @return
* Content of the CRC data register.
******************************************************************************/
__STATIC_INLINE uint32_t GPCRC_DataRead(GPCRC_TypeDef * gpcrc)
{
return gpcrc->DATA;
}
/***************************************************************************//**
* @brief
* Read the data register of the CRC bit reversed.
*
* @details
* Use this function to read the calculated CRC value bit reversed. When
* using a 32-bit polynomial, bits [31:0] are reversed, when using a
* 16-bit polynomial, bits [15:0] are reversed.
*
* @param[in] gpcrc
* Pointer to GPCRC peripheral register block.
*
* @return
* Content of the CRC data register bit reversed.
******************************************************************************/
__STATIC_INLINE uint32_t GPCRC_DataReadBitReversed(GPCRC_TypeDef * gpcrc)
{
return gpcrc->DATAREV;
}
/***************************************************************************//**
* @brief
* Read the data register of the CRC byte reversed.
*
* @details
* Use this function to read the calculated CRC value byte reversed.
*
* @param[in] gpcrc
* Pointer to GPCRC peripheral register block.
*
* @return
* Content of the CRC data register byte reversed.
******************************************************************************/
__STATIC_INLINE uint32_t GPCRC_DataReadByteReversed(GPCRC_TypeDef * gpcrc)
{
return gpcrc->DATABYTEREV;
}
/** @} (end addtogroup gpcrc) */
#ifdef __cplusplus
}
#endif
#endif /* defined(GPCRC_COUNT) && (GPCRC_COUNT > 0) */
#endif /* EM_GPCRC_H */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,525 @@
/***************************************************************************//**
* @file
* @brief Inter-integrated circuit (I2C) peripheral API
*******************************************************************************
* # License
* <b>Copyright 2018 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* 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.
*
******************************************************************************/
#ifndef EM_I2C_H
#define EM_I2C_H
#include "em_device.h"
#if defined(I2C_COUNT) && (I2C_COUNT > 0)
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
/***************************************************************************//**
* @addtogroup i2c
* @{
******************************************************************************/
/*******************************************************************************
******************************* DEFINES ***********************************
******************************************************************************/
/**
* @brief
* Standard mode max frequency assuming using 4:4 ratio for Nlow:Nhigh.
* @details
* From I2C specification: Min Tlow = 4.7us, min Thigh = 4.0us,
* max Trise=1.0us, max Tfall=0.3us. Since ratio is 4:4, have to use
* worst case value of Tlow or Thigh as base.
*
* 1/(Tlow + Thigh + 1us + 0.3us) = 1/(4.7 + 4.7 + 1.3)us = 93458Hz
* @note
* Due to chip characteristics, max value is somewhat reduced.
*/
#if defined(_SILICON_LABS_32B_SERIES_0) \
&& (defined(_EFM32_GECKO_FAMILY) \
|| defined(_EFM32_TINY_FAMILY) \
|| defined(_EFM32_ZERO_FAMILY) \
|| defined(_EFM32_HAPPY_FAMILY))
#define I2C_FREQ_STANDARD_MAX 93000
#elif defined(_SILICON_LABS_32B_SERIES_0) \
&& (defined(_EFM32_GIANT_FAMILY) \
|| defined(_EFM32_WONDER_FAMILY))
#define I2C_FREQ_STANDARD_MAX 92000
#elif defined(_SILICON_LABS_32B_SERIES_1)
// None of the chips on this platform has been characterized on this parameter.
// Use same value as on Wonder until further notice.
#define I2C_FREQ_STANDARD_MAX 92000
#elif defined(_SILICON_LABS_32B_SERIES_2)
#define I2C_FREQ_STANDARD_MAX 100000
#else
#error "Unknown device family."
#endif
/**
* @brief
* Fast mode max frequency assuming using 6:3 ratio for Nlow:Nhigh.
* @details
* From I2C specification: Min Tlow = 1.3us, min Thigh = 0.6us,
* max Trise=0.3us, max Tfall=0.3us. Since ratio is 6:3, have to use
* worst case value of Tlow or 2xThigh as base.
*
* 1/(Tlow + Thigh + 0.3us + 0.3us) = 1/(1.3 + 0.65 + 0.6)us = 392157Hz
*/
#define I2C_FREQ_FAST_MAX 392157
/**
* @brief
* Fast mode+ max frequency assuming using 11:6 ratio for Nlow:Nhigh.
* @details
* From I2C specification: Min Tlow = 0.5us, min Thigh = 0.26us,
* max Trise=0.12us, max Tfall=0.12us. Since ratio is 11:6, have to use
* worst case value of Tlow or (11/6)xThigh as base.
*
* 1/(Tlow + Thigh + 0.12us + 0.12us) = 1/(0.5 + 0.273 + 0.24)us = 987167Hz
*/
#define I2C_FREQ_FASTPLUS_MAX 987167
/**
* @brief
* Indicate plain write sequence: S+ADDR(W)+DATA0+P.
* @details
* @li S - Start
* @li ADDR(W) - address with W/R bit cleared
* @li DATA0 - Data taken from buffer with index 0
* @li P - Stop
*/
#define I2C_FLAG_WRITE 0x0001
/**
* @brief
* Indicate plain read sequence: S+ADDR(R)+DATA0+P.
* @details
* @li S - Start
* @li ADDR(R) - Address with W/R bit set
* @li DATA0 - Data read into buffer with index 0
* @li P - Stop
*/
#define I2C_FLAG_READ 0x0002
/**
* @brief
* Indicate combined write/read sequence: S+ADDR(W)+DATA0+Sr+ADDR(R)+DATA1+P.
* @details
* @li S - Start
* @li Sr - Repeated start
* @li ADDR(W) - Address with W/R bit cleared
* @li ADDR(R) - Address with W/R bit set
* @li DATAn - Data written from/read into buffer with index n
* @li P - Stop
*/
#define I2C_FLAG_WRITE_READ 0x0004
/**
* @brief
* Indicate write sequence using two buffers: S+ADDR(W)+DATA0+DATA1+P.
* @details
* @li S - Start
* @li ADDR(W) - Address with W/R bit cleared
* @li DATAn - Data written from buffer with index n
* @li P - Stop
*/
#define I2C_FLAG_WRITE_WRITE 0x0008
/** Use 10 bit address. */
#define I2C_FLAG_10BIT_ADDR 0x0010
/*******************************************************************************
******************************** ENUMS ************************************
******************************************************************************/
/** Clock low to high ratio settings. */
typedef enum {
i2cClockHLRStandard = _I2C_CTRL_CLHR_STANDARD, /**< Ratio is 4:4 */
i2cClockHLRAsymetric = _I2C_CTRL_CLHR_ASYMMETRIC, /**< Ratio is 6:3 */
i2cClockHLRFast = _I2C_CTRL_CLHR_FAST /**< Ratio is 11:3 */
} I2C_ClockHLR_TypeDef;
/** Return codes for single Controller mode transfer function. */
typedef enum {
/* In progress code (>0) */
i2cTransferInProgress = 1, /**< Transfer in progress. */
/* Complete code (=0) */
i2cTransferDone = 0, /**< Transfer completed successfully. */
/* Transfer error codes (<0). */
i2cTransferNack = -1, /**< NACK received during transfer. */
i2cTransferBusErr = -2, /**< Bus error during transfer (misplaced START/STOP). */
i2cTransferArbLost = -3, /**< Arbitration lost during transfer. */
i2cTransferUsageFault = -4, /**< Usage fault. */
i2cTransferSwFault = -5 /**< SW fault. */
} I2C_TransferReturn_TypeDef;
/*******************************************************************************
******************************* STRUCTS ***********************************
******************************************************************************/
/** I2C initialization structure. */
typedef struct {
/** Enable I2C peripheral when initialization completed. */
bool enable;
/** Set to Controller (true) or Target (false) mode */
bool master;
/**
* I2C reference clock assumed when configuring bus frequency setup.
* Set it to 0 if currently configured reference clock will be used
* This parameter is only applicable if operating in Controller mode.
*/
uint32_t refFreq;
/**
* (Max) I2C bus frequency to use. This parameter is only applicable
* if operating in Controller mode.
*/
uint32_t freq;
/** Clock low/high ratio control. */
I2C_ClockHLR_TypeDef clhr;
} I2C_Init_TypeDef;
/** Suggested default configuration for I2C initialization structure. */
#define I2C_INIT_DEFAULT \
{ \
true, /* Enable when initialization done. */ \
true, /* Set to Controller mode. */ \
0, /* Use currently configured reference clock. */ \
I2C_FREQ_STANDARD_MAX, /* Set to standard rate assuring being */ \
/* within I2C specification. */ \
i2cClockHLRStandard /* Set to use 4:4 low/high duty cycle. */ \
}
/**
* @brief
* Master mode transfer message structure used to define a complete
* I2C transfer sequence (from start to stop).
* @details
* The structure allows for defining the following types of sequences
* (refer to defines for sequence details):
* @li #I2C_FLAG_READ - Data read into buf[0].data
* @li #I2C_FLAG_WRITE - Data written from buf[0].data
* @li #I2C_FLAG_WRITE_READ - Data written from buf[0].data and read
* into buf[1].data
* @li #I2C_FLAG_WRITE_WRITE - Data written from buf[0].data and
* buf[1].data
*/
typedef struct {
/**
* @brief
* Address to use after (repeated) start.
* @details
* Layout details, A = Address bit, X = don't care bit (set to 0):
* @li 7 bit address - Use format AAAA AAAX
* @li 10 bit address - Use format XXXX XAAX AAAA AAAA
*/
uint16_t addr;
/** Flags defining sequence type and details, see I2C_FLAG_ defines. */
uint16_t flags;
/**
* Buffers used to hold data to send from or receive into, depending
* on sequence type.
*/
struct {
/** Buffer used for data to transmit/receive, must be @p len long. */
uint8_t *data;
/**
* Number of bytes in @p data to send or receive. Notice that when
* receiving data to this buffer, at least 1 byte must be received.
* Setting @p len to 0 in the receive case is considered a usage fault.
* Transmitting 0 bytes is legal, in which case only the address
* is transmitted after the start condition.
*/
uint16_t len;
} buf[2];
} I2C_TransferSeq_TypeDef;
/*******************************************************************************
***************************** PROTOTYPES **********************************
******************************************************************************/
uint32_t I2C_BusFreqGet(I2C_TypeDef *i2c);
void I2C_BusFreqSet(I2C_TypeDef *i2c,
uint32_t freqRef,
uint32_t freqScl,
I2C_ClockHLR_TypeDef i2cMode);
void I2C_Enable(I2C_TypeDef *i2c, bool enable);
void I2C_Init(I2C_TypeDef *i2c, const I2C_Init_TypeDef *init);
/***************************************************************************//**
* @brief
* Clear one or more pending I2C interrupts.
*
* @param[in] i2c
* Pointer to I2C peripheral register block.
*
* @param[in] flags
* Pending I2C interrupt source to clear. Use a bitwise logic OR combination of
* valid interrupt flags for the I2C module (I2C_IF_nnn).
******************************************************************************/
__STATIC_INLINE void I2C_IntClear(I2C_TypeDef *i2c, uint32_t flags)
{
#if defined (I2C_HAS_SET_CLEAR)
i2c->IF_CLR = flags;
#else
i2c->IFC = flags;
#endif
}
/***************************************************************************//**
* @brief
* Disable one or more I2C interrupts.
*
* @param[in] i2c
* Pointer to I2C peripheral register block.
*
* @param[in] flags
* I2C interrupt sources to disable. Use a bitwise logic OR combination of
* valid interrupt flags for the I2C module (I2C_IF_nnn).
******************************************************************************/
__STATIC_INLINE void I2C_IntDisable(I2C_TypeDef *i2c, uint32_t flags)
{
#if defined (I2C_HAS_SET_CLEAR)
i2c->IEN_CLR = flags;
#else
i2c->IEN &= ~(flags);
#endif
}
/***************************************************************************//**
* @brief
* Enable one or more I2C interrupts.
*
* @note
* Depending on the use, a pending interrupt may already be set prior to
* enabling the interrupt. To ignore a pending interrupt, consider using
* I2C_IntClear() prior to enabling the interrupt.
*
* @param[in] i2c
* Pointer to I2C peripheral register block.
*
* @param[in] flags
* I2C interrupt sources to enable. Use a bitwise logic OR combination of
* valid interrupt flags for the I2C module (I2C_IF_nnn).
******************************************************************************/
__STATIC_INLINE void I2C_IntEnable(I2C_TypeDef *i2c, uint32_t flags)
{
#if defined (I2C_HAS_SET_CLEAR)
i2c->IEN_SET = flags;
#else
i2c->IEN |= flags;
#endif
}
/***************************************************************************//**
* @brief
* Get pending I2C interrupt flags.
*
* @note
* Event bits are not cleared by the use of this function.
*
* @param[in] i2c
* Pointer to I2C peripheral register block.
*
* @return
* I2C interrupt sources pending. A bitwise logic OR combination of valid
* interrupt flags for the I2C module (I2C_IF_nnn).
******************************************************************************/
__STATIC_INLINE uint32_t I2C_IntGet(I2C_TypeDef *i2c)
{
return i2c->IF;
}
/***************************************************************************//**
* @brief
* Get enabled and pending I2C interrupt flags.
* Useful for handling more interrupt sources in the same interrupt handler.
*
* @note
* Interrupt flags are not cleared by the use of this function.
*
* @param[in] i2c
* Pointer to I2C peripheral register block.
*
* @return
* Pending and enabled I2C interrupt sources
* Return value is the bitwise AND of
* - the enabled interrupt sources in I2Cn_IEN and
* - the pending interrupt flags I2Cn_IF
******************************************************************************/
__STATIC_INLINE uint32_t I2C_IntGetEnabled(I2C_TypeDef *i2c)
{
uint32_t ien;
ien = i2c->IEN;
return i2c->IF & ien;
}
/***************************************************************************//**
* @brief
* Set one or more pending I2C interrupts from SW.
*
* @param[in] i2c
* Pointer to I2C peripheral register block.
*
* @param[in] flags
* I2C interrupt sources to set to pending. Use a bitwise logic OR combination
* of valid interrupt flags for the I2C module (I2C_IF_nnn).
******************************************************************************/
__STATIC_INLINE void I2C_IntSet(I2C_TypeDef *i2c, uint32_t flags)
{
#if defined (I2C_HAS_SET_CLEAR)
i2c->IF_SET = flags;
#else
i2c->IFS = flags;
#endif
}
void I2C_Reset(I2C_TypeDef *i2c);
/***************************************************************************//**
* @brief
* Get Target address used for I2C peripheral (when operating in Target mode).
*
* @details
* For 10-bit addressing mode, the address is split in two bytes, and only
* the first byte setting is fetched, effectively only controlling the 2 most
* significant bits of the 10-bit address. Full handling of 10-bit addressing
* in Target mode requires additional SW handling.
*
* @param[in] i2c
* Pointer to I2C peripheral register block.
*
* @return
* I2C Target address in use. The 7 most significant bits define the actual
* address, the least significant bit is reserved and always returned as 0.
******************************************************************************/
__STATIC_INLINE uint8_t I2C_SlaveAddressGet(I2C_TypeDef *i2c)
{
return ((uint8_t)(i2c->SADDR));
}
/***************************************************************************//**
* @brief
* Set Target address to use for I2C peripheral (when operating in Target mode).
*
* @details
* For 10- bit addressing mode, the address is split in two bytes, and only
* the first byte is set, effectively only controlling the 2 most significant
* bits of the 10-bit address. Full handling of 10-bit addressing in Target
* mode requires additional SW handling.
*
* @param[in] i2c
* Pointer to I2C peripheral register block.
*
* @param[in] addr
* I2C Target address to use. The 7 most significant bits define the actual
* address, the least significant bit is reserved and always set to 0.
******************************************************************************/
__STATIC_INLINE void I2C_SlaveAddressSet(I2C_TypeDef *i2c, uint8_t addr)
{
i2c->SADDR = (uint32_t)addr & 0xfe;
}
/***************************************************************************//**
* @brief
* Get Target address mask used for I2C peripheral (when operating in Target
* mode).
*
* @details
* The address mask defines how the comparator works. A bit position with
* value 0 means that the corresponding Target address bit is ignored during
* comparison (don't care). A bit position with value 1 means that the
* corresponding Target address bit must match.
*
* For 10-bit addressing mode, the address is split in two bytes, and only
* the mask for the first address byte is fetched, effectively only
* controlling the 2 most significant bits of the 10-bit address.
*
* @param[in] i2c
* Pointer to I2C peripheral register block.
*
* @return
* I2C Target address mask in use. The 7 most significant bits define the
* actual address mask, the least significant bit is reserved and always
* returned as 0.
******************************************************************************/
__STATIC_INLINE uint8_t I2C_SlaveAddressMaskGet(I2C_TypeDef *i2c)
{
return ((uint8_t)(i2c->SADDRMASK));
}
/***************************************************************************//**
* @brief
* Set Target address mask used for I2C peripheral (when operating in Target
* mode).
*
* @details
* The address mask defines how the comparator works. A bit position with
* value 0 means that the corresponding Target address bit is ignored during
* comparison (don't care). A bit position with value 1 means that the
* corresponding Target address bit must match.
*
* For 10-bit addressing mode, the address is split in two bytes, and only
* the mask for the first address byte is set, effectively only controlling
* the 2 most significant bits of the 10-bit address.
*
* @param[in] i2c
* Pointer to I2C peripheral register block.
*
* @param[in] mask
* I2C Target address mask to use. The 7 most significant bits define the
* actual address mask, the least significant bit is reserved and should
* be 0.
******************************************************************************/
__STATIC_INLINE void I2C_SlaveAddressMaskSet(I2C_TypeDef *i2c, uint8_t mask)
{
i2c->SADDRMASK = (uint32_t)mask & 0xfe;
}
I2C_TransferReturn_TypeDef I2C_Transfer(I2C_TypeDef *i2c);
I2C_TransferReturn_TypeDef I2C_TransferInit(I2C_TypeDef *i2c,
I2C_TransferSeq_TypeDef *seq);
/** @} (end addtogroup i2c) */
#ifdef __cplusplus
}
#endif
#endif /* defined(I2C_COUNT) && (I2C_COUNT > 0) */
#endif /* EM_I2C_H */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,334 @@
/***************************************************************************//**
* @file
* @brief Low Energy Timer (LETIMER) peripheral API
*******************************************************************************
* # License
* <b>Copyright 2018 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* 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.
*
******************************************************************************/
#ifndef EM_LETIMER_H
#define EM_LETIMER_H
#include <stdbool.h>
#include "em_device.h"
#if defined(LETIMER_COUNT) && (LETIMER_COUNT > 0)
#ifdef __cplusplus
extern "C" {
#endif
/***************************************************************************//**
* @addtogroup letimer
* @{
******************************************************************************/
/*******************************************************************************
******************************** ENUMS ************************************
******************************************************************************/
/** Repeat mode. */
typedef enum {
/** Count until stopped by SW. */
letimerRepeatFree = _LETIMER_CTRL_REPMODE_FREE,
/** Count REP0 times. */
letimerRepeatOneshot = _LETIMER_CTRL_REPMODE_ONESHOT,
/**
* Count REP0 times, if REP1 has been written to, it is loaded into
* REP0 when REP0 is about to be decremented to 0.
*/
letimerRepeatBuffered = _LETIMER_CTRL_REPMODE_BUFFERED,
/**
* Run as long as both REP0 and REP1 are not 0. Both REP0 and REP1
* are decremented when counter underflows.
*/
letimerRepeatDouble = _LETIMER_CTRL_REPMODE_DOUBLE
} LETIMER_RepeatMode_TypeDef;
/** Underflow action on output. */
typedef enum {
/** No output action. */
letimerUFOANone = _LETIMER_CTRL_UFOA0_NONE,
/** Toggle output when counter underflows. */
letimerUFOAToggle = _LETIMER_CTRL_UFOA0_TOGGLE,
/** Hold output one LETIMER clock cycle when counter underflows. */
letimerUFOAPulse = _LETIMER_CTRL_UFOA0_PULSE,
/** Set output idle when counter underflows, and active when matching COMP1. */
letimerUFOAPwm = _LETIMER_CTRL_UFOA0_PWM
} LETIMER_UFOA_TypeDef;
/*******************************************************************************
******************************* STRUCTS ***********************************
******************************************************************************/
/** LETIMER initialization structure. */
typedef struct {
bool enable; /**< Start counting when initialization completes. */
bool debugRun; /**< Counter shall keep running during debug halt. */
#if defined(LETIMER_CTRL_RTCC0TEN)
bool rtcComp0Enable; /**< Start counting on RTC COMP0 match. */
bool rtcComp1Enable; /**< Start counting on RTC COMP1 match. */
#endif
bool comp0Top; /**< Load COMP0 register into CNT when counter underflows. */
bool bufTop; /**< Load COMP1 into COMP0 when REP0 reaches 0. */
uint8_t out0Pol; /**< Idle value for output 0. */
uint8_t out1Pol; /**< Idle value for output 1. */
LETIMER_UFOA_TypeDef ufoa0; /**< Underflow output 0 action. */
LETIMER_UFOA_TypeDef ufoa1; /**< Underflow output 1 action. */
LETIMER_RepeatMode_TypeDef repMode; /**< Repeat mode. */
uint32_t topValue; /**< Top value. Counter wraps when top value matches counter value is reached. */
} LETIMER_Init_TypeDef;
/** Default configuration for LETIMER initialization structure. */
#if defined(LETIMER_CTRL_RTCC0TEN)
#define LETIMER_INIT_DEFAULT \
{ \
true, /* Enable timer when initialization completes. */ \
false, /* Stop counter during debug halt. */ \
false, /* Do not start counting on RTC COMP0 match. */ \
false, /* Do not start counting on RTC COMP1 match. */ \
false, /* Do not load COMP0 into CNT on underflow. */ \
false, /* Do not load COMP1 into COMP0 when REP0 reaches 0. */ \
0, /* Idle value 0 for output 0. */ \
0, /* Idle value 0 for output 1. */ \
letimerUFOANone, /* No action on underflow on output 0. */ \
letimerUFOANone, /* No action on underflow on output 1. */ \
letimerRepeatFree, /* Count until stopped by SW. */ \
0 /* Use default top Value. */ \
}
#else
#define LETIMER_INIT_DEFAULT \
{ \
true, /* Enable timer when initialization completes. */ \
false, /* Stop counter during debug halt. */ \
false, /* Do not load COMP0 into CNT on underflow. */ \
false, /* Do not load COMP1 into COMP0 when REP0 reaches 0. */ \
0, /* Idle value 0 for output 0. */ \
0, /* Idle value 0 for output 1. */ \
letimerUFOANone, /* No action on underflow on output 0. */ \
letimerUFOANone, /* No action on underflow on output 1. */ \
letimerRepeatFree, /* Count until stopped by SW. */ \
0 /* Use default top Value. */ \
}
#endif
/*******************************************************************************
***************************** PROTOTYPES **********************************
******************************************************************************/
uint32_t LETIMER_CompareGet(LETIMER_TypeDef *letimer, unsigned int comp);
void LETIMER_CompareSet(LETIMER_TypeDef *letimer,
unsigned int comp,
uint32_t value);
uint32_t LETIMER_CounterGet(LETIMER_TypeDef *letimer);
#if !defined(_EFM32_GECKO_FAMILY)
void LETIMER_CounterSet(LETIMER_TypeDef *letimer, uint32_t value);
#endif
void LETIMER_Enable(LETIMER_TypeDef *letimer, bool enable);
#if defined(_LETIMER_FREEZE_MASK)
void LETIMER_FreezeEnable(LETIMER_TypeDef *letimer, bool enable);
#endif
void LETIMER_Init(LETIMER_TypeDef *letimer, const LETIMER_Init_TypeDef *init);
/***************************************************************************//**
* @brief
* Clear one or more pending LETIMER interrupts.
*
* @param[in] letimer
* Pointer to LETIMER peripheral register block.
*
* @param[in] flags
* Pending LETIMER interrupt source to clear. Use a bitwise logic OR
* combination of valid interrupt flags for the LETIMER module
* (LETIMER_IF_nnn).
******************************************************************************/
__STATIC_INLINE void LETIMER_IntClear(LETIMER_TypeDef *letimer, uint32_t flags)
{
#if defined (LETIMER_HAS_SET_CLEAR)
letimer->IF_CLR = flags;
#else
letimer->IFC = flags;
#endif
}
/***************************************************************************//**
* @brief
* Disable one or more LETIMER interrupts.
*
* @param[in] letimer
* Pointer to LETIMER peripheral register block.
*
* @param[in] flags
* LETIMER interrupt sources to disable. Use a bitwise logic OR combination of
* valid interrupt flags for the LETIMER module (LETIMER_IF_nnn).
******************************************************************************/
__STATIC_INLINE void LETIMER_IntDisable(LETIMER_TypeDef *letimer, uint32_t flags)
{
letimer->IEN &= ~flags;
}
/***************************************************************************//**
* @brief
* Enable one or more LETIMER interrupts.
*
* @note
* Depending on the use, a pending interrupt may already be set prior to
* enabling the interrupt. To ignore a pending interrupt, consider using
* LETIMER_IntClear() prior to enabling the interrupt.
*
* @param[in] letimer
* Pointer to the LETIMER peripheral register block.
*
* @param[in] flags
* LETIMER interrupt sources to enable. Use a bitwise logic OR combination of
* valid interrupt flags for the LETIMER module (LETIMER_IF_nnn).
******************************************************************************/
__STATIC_INLINE void LETIMER_IntEnable(LETIMER_TypeDef *letimer, uint32_t flags)
{
letimer->IEN |= flags;
}
/***************************************************************************//**
* @brief
* Get pending LETIMER interrupt flags.
*
* @note
* Event bits are not cleared by the use of this function.
*
* @param[in] letimer
* Pointer to LETIMER peripheral register block.
*
* @return
* LETIMER interrupt sources pending. A bitwise logic OR combination of
* valid interrupt flags for the LETIMER module (LETIMER_IF_nnn).
******************************************************************************/
__STATIC_INLINE uint32_t LETIMER_IntGet(LETIMER_TypeDef *letimer)
{
return letimer->IF;
}
/***************************************************************************//**
* @brief
* Get enabled and pending LETIMER interrupt flags.
*
* @details
* Useful for handling more interrupt sources in the same interrupt handler.
*
* @note
* Event bits are not cleared by the use of this function.
*
* @param[in] letimer
* Pointer to LETIMER peripheral register block.
*
* @return
* Pending and enabled LETIMER interrupt sources.
* Return value is the bitwise AND combination of
* - the OR combination of enabled interrupt sources in LETIMER_IEN_nnn
* register (LETIMER_IEN_nnn) and
* - the OR combination of valid interrupt flags of the LETIMER module
* (LETIMER_IF_nnn).
******************************************************************************/
__STATIC_INLINE uint32_t LETIMER_IntGetEnabled(LETIMER_TypeDef *letimer)
{
uint32_t ien;
/* Store flags in temporary variable in order to define explicit order
* of volatile accesses. */
ien = letimer->IEN;
/* Bitwise AND of pending and enabled interrupts */
return letimer->IF & ien;
}
/***************************************************************************//**
* @brief
* Set one or more pending LETIMER interrupts from SW.
*
* @param[in] letimer
* Pointer to LETIMER peripheral register block.
*
* @param[in] flags
* LETIMER interrupt sources to set to pending. Use a bitwise logic OR
* combination of valid interrupt flags for the LETIMER module (LETIMER_IF_nnn).
******************************************************************************/
__STATIC_INLINE void LETIMER_IntSet(LETIMER_TypeDef *letimer, uint32_t flags)
{
#if defined (LETIMER_HAS_SET_CLEAR)
letimer->IF_SET = flags;
#else
letimer->IFS = flags;
#endif
}
#if defined(_LETIMER_LOCK_MASK)
/***************************************************************************//**
* @brief
* Lock LETIMER registers.
*
* @param[in] letimer
* Pointer to LETIMER peripheral register block.
*
* @note When LETIMER registers are locked LETIMER_EN, LETIMER_SWRST,
* LETIMER_CTRL, LETIMER_CMD, LETIMER_CNT, LETIMER_COMPx,
* LETIMER_TOP, LETIMER_TOPBUFF, LETIMER_REPx, and PRSMODE registers
* cannot be written to.
******************************************************************************/
__STATIC_INLINE void LETIMER_Lock(LETIMER_TypeDef *letimer)
{
letimer->LOCK = ~LETIMER_LOCK_LETIMERLOCKKEY_UNLOCK;
}
#endif
#if defined(_LETIMER_LOCK_MASK)
/***************************************************************************//**
* @brief
* Unlock LETIMER registers.
*
* @param[in] letimer
* Pointer to LETIMER peripheral register block.
******************************************************************************/
__STATIC_INLINE void LETIMER_Unlock(LETIMER_TypeDef *letimer)
{
letimer->LOCK = LETIMER_LOCK_LETIMERLOCKKEY_UNLOCK;
}
#endif
uint32_t LETIMER_RepeatGet(LETIMER_TypeDef *letimer, unsigned int rep);
void LETIMER_RepeatSet(LETIMER_TypeDef *letimer,
unsigned int rep,
uint32_t value);
void LETIMER_Reset(LETIMER_TypeDef *letimer);
void LETIMER_SyncWait(LETIMER_TypeDef *letimer);
void LETIMER_TopSet(LETIMER_TypeDef *letimer, uint32_t value);
uint32_t LETIMER_TopGet(LETIMER_TypeDef *letimer);
/** @} (end addtogroup letimer) */
#ifdef __cplusplus
}
#endif
#endif /* defined(LETIMER_COUNT) && (LETIMER_COUNT > 0) */
#endif /* EM_LETIMER_H */

View File

@@ -0,0 +1,889 @@
/***************************************************************************//**
* @file
* @brief Flash Controller (MSC) Peripheral API
*******************************************************************************
* # License
* <b>Copyright 2018 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* 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.
*
******************************************************************************/
#ifndef EM_MSC_H
#define EM_MSC_H
#include "em_device.h"
#if defined(MSC_COUNT) && (MSC_COUNT > 0)
#include <stdint.h>
#include <stdbool.h>
#include "em_bus.h"
#include "em_msc_compat.h"
#include "em_ramfunc.h"
#include "sl_assert.h"
#if defined(SL_CATALOG_TZ_SECURE_KEY_LIBRARY_NS_PRESENT)
#include "sli_tz_ns_interface.h"
#include "sli_tz_service_msc.h"
#include "sli_tz_s_interface.h"
#endif
#ifdef __cplusplus
extern "C" {
#endif
/***************************************************************************//**
* @addtogroup msc MSC - Memory System Controller
* @brief Memory System Controller API
* @details
* Contains functions to control the MSC, primarily the Flash.
* Users can perform Flash memory write and erase operations, as well as
* optimization of the CPU instruction fetch interface for the application.
* Available instruction fetch features depends on the MCU or SoC family, but
* features such as instruction pre-fetch, cache, and configurable branch prediction
* are typically available.
*
* @note Flash wait-state configuration is handled by @ref cmu.
* When core clock configuration is changed by a call to functions such as
* CMU_ClockSelectSet() or CMU_HFRCOBandSet(), then Flash wait-state
* configuration is also updated.
*
* MSC resets into a safe state. To initialize the instruction interface
* to recommended settings:
* @include em_msc_init_exec.c
*
* @note The optimal configuration is highly application dependent. Performance
* benchmarking is supported by most families. See MSC_StartCacheMeasurement()
* and MSC_GetCacheMeasurement() for more details.
*
* @note
* The flash write and erase runs from RAM on the EFM32G devices. On all other
* devices the flash write and erase functions run from flash.
*
* @note
* Flash erase may add ms of delay to interrupt latency if executing from Flash.
*
* Flash write and erase operations are supported by @ref MSC_WriteWord(),
* @ref MSC_ErasePage(), and MSC_MassErase().
* Mass erase is supported for MCU and SoC families with larger Flash sizes.
*
* @note
* @ref MSC_Init() must be called prior to any Flash write or erase operation.
*
* The following steps are necessary to perform a page erase and write:
* @include em_msc_erase_write.c
*
* @deprecated
* The configuration called EM_MSC_RUN_FROM_FLASH is deprecated. This was
* previously used for allocating the flash write functions in either flash
* or RAM.
*
* @note
* The configuration EM_MSC_RUN_FROM_RAM is used to allocate the flash
* write functions in RAM. By default, flash write
* functions are placed in RAM on EFM32G and Series 2 devices
* unless SL_RAMFUNC_DISABLE is defined. For other devices,
* flash write functions are placed in FLASH by default unless
* EM_MSC_RUN_FROM_RAM is defined and SL_RAMFUNC_DISABLE is not defined.
*
* @deprecated
* The function called MSC_WriteWordFast() is deprecated.
*
* @{
******************************************************************************/
/*******************************************************************************
************************* DEFINES *****************************************
******************************************************************************/
/**
* @brief
* Timeout used while waiting for Flash to become ready after a write.
* This number indicates the number of iterations to perform before
* issuing a timeout.
*
* @note
* Timeout is set very large (in the order of 100x longer than
* necessary). This is to avoid any corner case.
*/
#define MSC_PROGRAM_TIMEOUT 10000000UL
/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
#if (defined(_EFM32_GECKO_FAMILY) \
|| defined(_SILICON_LABS_32B_SERIES_2) \
|| defined(EM_MSC_RUN_FROM_RAM)) \
&& !defined(SL_CATALOG_TZ_SECURE_KEY_LIBRARY_NS_PRESENT)
#define MSC_RAMFUNC_DECLARATOR SL_RAMFUNC_DECLARATOR
#define MSC_RAMFUNC_DEFINITION_BEGIN SL_RAMFUNC_DEFINITION_BEGIN
#define MSC_RAMFUNC_DEFINITION_END SL_RAMFUNC_DEFINITION_END
#else
#define MSC_RAMFUNC_DECLARATOR
#define MSC_RAMFUNC_DEFINITION_BEGIN
#define MSC_RAMFUNC_DEFINITION_END
#endif
/** @endcond */
/*******************************************************************************
************************* TYPEDEFS ****************************************
******************************************************************************/
/** Return codes for writing/erasing Flash. */
typedef enum {
mscReturnOk = 0, /**< Flash write/erase successful. */
mscReturnInvalidAddr = -1, /**< Invalid address. Write to an address that is not Flash. */
mscReturnLocked = -2, /**< Flash address is locked. */
mscReturnTimeOut = -3, /**< Timeout while writing to Flash. */
mscReturnUnaligned = -4 /**< Unaligned access to Flash. */
} MSC_Status_TypeDef;
#if defined(_MSC_READCTRL_BUSSTRATEGY_MASK)
/** Strategy for prioritized bus access. */
typedef enum {
mscBusStrategyCPU = MSC_READCTRL_BUSSTRATEGY_CPU, /**< Prioritize CPU bus accesses. */
mscBusStrategyDMA = MSC_READCTRL_BUSSTRATEGY_DMA, /**< Prioritize DMA bus accesses. */
mscBusStrategyDMAEM1 = MSC_READCTRL_BUSSTRATEGY_DMAEM1, /**< Prioritize DMAEM1 for bus accesses. */
mscBusStrategyNone = MSC_READCTRL_BUSSTRATEGY_NONE /**< No unit has bus priority. */
} MSC_BusStrategy_Typedef;
#endif
#if defined(_SYSCFG_DMEM0PORTMAPSEL_MASK)
/** AHBHOST masters that can use alternate MPAHBRAM ports. */
typedef enum {
mscDmemMasterLDMA = _SYSCFG_DMEM0PORTMAPSEL_LDMAPORTSEL_SHIFT,
mscDmemMasterSRWAES = _SYSCFG_DMEM0PORTMAPSEL_SRWAESPORTSEL_SHIFT,
mscDmemMasterAHBSRW = _SYSCFG_DMEM0PORTMAPSEL_AHBSRWPORTSEL_SHIFT,
#if defined(_SYSCFG_DMEM0PORTMAPSEL_IFADCDEBUGPORTSEL_MASK)
mscDmemMasterIFADCDEBUG = _SYSCFG_DMEM0PORTMAPSEL_IFADCDEBUGPORTSEL_SHIFT,
#endif
#if defined(_SYSCFG_DMEM0PORTMAPSEL_SRWECA0PORTSEL_MASK)
mscDmemMasterSRWECA0 = _SYSCFG_DMEM0PORTMAPSEL_SRWECA0PORTSEL_SHIFT,
#endif
#if defined(_SYSCFG_DMEM0PORTMAPSEL_SRWECA1PORTSEL_MASK)
mscDmemMasterSRWECA1 = _SYSCFG_DMEM0PORTMAPSEL_SRWECA1PORTSEL_SHIFT,
#endif
#if defined(_SYSCFG_DMEM0PORTMAPSEL_MVPAHBDATA0PORTSEL_MASK)
mscDmemMasterMVPAHBDATA0 = _SYSCFG_DMEM0PORTMAPSEL_MVPAHBDATA0PORTSEL_SHIFT,
#endif
#if defined(_SYSCFG_DMEM0PORTMAPSEL_MVPAHBDATA1PORTSEL_MASK)
mscDmemMasterMVPAHBDATA1 = _SYSCFG_DMEM0PORTMAPSEL_MVPAHBDATA1PORTSEL_SHIFT,
#endif
#if defined(_SYSCFG_DMEM0PORTMAPSEL_MVPAHBDATA2PORTSEL_MASK)
mscDmemMasterMVPAHBDATA2 = _SYSCFG_DMEM0PORTMAPSEL_MVPAHBDATA2PORTSEL_SHIFT,
#endif
#if defined(_SYSCFG_DMEM0PORTMAPSEL_LDMA1PORTSEL_MASK)
mscDmemMasterLDMA1 = _SYSCFG_DMEM0PORTMAPSEL_LDMA1PORTSEL_SHIFT,
#endif
#if defined(_SYSCFG_DMEM0PORTMAPSEL_SRWLDMAPORTSEL_MASK)
mscDmemMasterSRWLDMA = _SYSCFG_DMEM0PORTMAPSEL_SRWLDMAPORTSEL_SHIFT,
#endif
#if defined(_SYSCFG_DMEM0PORTMAPSEL_USBPORTSEL_MASK)
mscDmemMasterUSB = _SYSCFG_DMEM0PORTMAPSEL_USBPORTSEL_SHIFT,
#endif
#if defined(_SYSCFG_DMEM0PORTMAPSEL_BUFCPORTSEL_MASK)
mscDmemMasterBUFC = _SYSCFG_DMEM0PORTMAPSEL_BUFCPORTSEL_SHIFT
#endif
} MSC_DmemMaster_TypeDef;
#endif
#if defined(_MPAHBRAM_CTRL_AHBPORTPRIORITY_MASK)
/** AHB port given priority. */
typedef enum {
mscPortPriorityNone = _MPAHBRAM_CTRL_AHBPORTPRIORITY_NONE,
mscPortPriorityPort0 = _MPAHBRAM_CTRL_AHBPORTPRIORITY_PORT0,
mscPortPriorityPort1 = _MPAHBRAM_CTRL_AHBPORTPRIORITY_PORT1,
#if defined(_MPAHBRAM_CTRL_AHBPORTPRIORITY_PORT2)
mscPortPriorityPort2 = _MPAHBRAM_CTRL_AHBPORTPRIORITY_PORT2,
#endif
#if defined(_MPAHBRAM_CTRL_AHBPORTPRIORITY_PORT3)
mscPortPriorityPort3 = _MPAHBRAM_CTRL_AHBPORTPRIORITY_PORT3,
#endif
} MSC_PortPriority_TypeDef;
#endif
#if defined(MSC_READCTRL_DOUTBUFEN) || defined(MSC_RDATACTRL_DOUTBUFEN)
/** Code execution configuration */
typedef struct {
bool doutBufEn; /**< Flash dout pipeline buffer enable */
} MSC_ExecConfig_TypeDef;
/** Default MSC ExecConfig initialization */
#define MSC_EXECCONFIG_DEFAULT \
{ \
false, \
}
#else
/** Code execution configuration. */
typedef struct {
bool scbtEn; /**< Enable Suppressed Conditional Branch Target Prefetch. */
bool prefetchEn; /**< Enable MSC prefetching. */
bool ifcDis; /**< Disable instruction cache. */
bool aiDis; /**< Disable automatic cache invalidation on write or erase. */
bool iccDis; /**< Disable automatic caching of fetches in interrupt context. */
bool useHprot; /**< Use ahb_hprot to determine if the instruction is cacheable or not. */
} MSC_ExecConfig_TypeDef;
/** Default MSC ExecConfig initialization. */
#define MSC_EXECCONFIG_DEFAULT \
{ \
false, \
true, \
false, \
false, \
false, \
false, \
}
#endif
#if defined(_MSC_ECCCTRL_MASK) \
|| defined(_SYSCFG_DMEM0ECCCTRL_MASK) \
|| defined(_MPAHBRAM_CTRL_MASK)
#if defined(_SILICON_LABS_32B_SERIES_1_CONFIG_1)
/** EFM32GG11B incorporates 2 memory banks including ECC support. */
#define MSC_ECC_BANKS (2)
/** Default MSC EccConfig initialization. */
#define MSC_ECCCONFIG_DEFAULT \
{ \
{ false, false }, \
{ 0, 1 }, \
}
#elif defined(_SILICON_LABS_GECKO_INTERNAL_SDID_106)
/** EFM32GG12B incorporates 3 memory banks including ECC support. */
#define MSC_ECC_BANKS (3)
/** Default MSC EccConfig initialization. */
#define MSC_ECCCONFIG_DEFAULT \
{ \
{ false, false, false }, \
{ 0, 1 }, \
}
#elif defined(_SILICON_LABS_32B_SERIES_2_CONFIG_6)
/** xG26 chips incorporate 2 memory banks including ECC support. */
#define MSC_ECC_BANKS (2)
/** Default MSC EccConfig initialization */
#define MSC_ECCCONFIG_DEFAULT \
{ \
{ false, false }, \
{ 0, 1 }, \
}
#elif defined(_SILICON_LABS_32B_SERIES_2)
/** Series 2 chips incorporate 1 memory bank including ECC support. */
#define MSC_ECC_BANKS (1)
/** Default MSC EccConfig initialization */
#define MSC_ECCCONFIG_DEFAULT \
{ \
{ false }, \
{ 0, 1 }, \
}
#else
#error Device not supported.
#endif
/** ECC configuration. */
typedef struct {
bool enableEccBank[MSC_ECC_BANKS]; /**< Array of bools to enable/disable
Error Correcting Code (ECC) for
each RAM bank that supports ECC on
the device. */
uint32_t dmaChannels[2]; /**< Array of 2 DMA channel numbers to
use for ECC initialization. */
} MSC_EccConfig_TypeDef;
#endif /* #if defined(_MSC_ECCCTRL_MASK) */
/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
/* Deprecated type names. */
#define mscBusStrategy_Typedef MSC_BusStrategy_Typedef
#define msc_Return_TypeDef MSC_Status_TypeDef
/** @endcond */
/*******************************************************************************
************************* Inline Functions ********************************
******************************************************************************/
/***************************************************************************//**
* @brief
* Get the status of the MSC register lock.
*
* @return
* Boolean true if register lock is applied, false otherwise.
******************************************************************************/
__STATIC_INLINE bool MSC_LockGetLocked(void)
{
#if defined(SL_CATALOG_TZ_SECURE_KEY_LIBRARY_NS_PRESENT)
return (bool)sli_tz_ns_interface_dispatch_simple_noarg(
(sli_tz_veneer_simple_noarg_fn)sli_tz_s_interface_dispatch_simple_no_args,
SLI_TZ_MSC_GET_LOCKED_SID);
#elif defined(_MSC_STATUS_REGLOCK_MASK)
return (MSC->STATUS & _MSC_STATUS_REGLOCK_MASK) != MSC_STATUS_REGLOCK_UNLOCKED;
#else
return (MSC->LOCK & _MSC_LOCK_MASK) != MSC_LOCK_LOCKKEY_UNLOCKED;
#endif
}
/***************************************************************************//**
* @brief
* Set the MSC register lock to a locked state.
******************************************************************************/
__STATIC_INLINE void MSC_LockSetLocked(void)
{
#if defined(SL_CATALOG_TZ_SECURE_KEY_LIBRARY_NS_PRESENT)
(void)sli_tz_ns_interface_dispatch_simple_noarg(
(sli_tz_veneer_simple_noarg_fn)sli_tz_s_interface_dispatch_simple_no_args,
SLI_TZ_MSC_SET_LOCKED_SID);
#else
MSC->LOCK = MSC_LOCK_LOCKKEY_LOCK;
#endif
}
/***************************************************************************//**
* @brief
* Set the MSC register lock to an unlocked state.
******************************************************************************/
__STATIC_INLINE void MSC_LockSetUnlocked(void)
{
#if defined(SL_CATALOG_TZ_SECURE_KEY_LIBRARY_NS_PRESENT)
(void)sli_tz_ns_interface_dispatch_simple_noarg(
(sli_tz_veneer_simple_noarg_fn)sli_tz_s_interface_dispatch_simple_no_args,
SLI_TZ_MSC_SET_UNLOCKED_SID);
#else
MSC->LOCK = MSC_LOCK_LOCKKEY_UNLOCK;
#endif
}
/***************************************************************************//**
* @brief
* Get the current value of the read control register (MSC_READCTRL).
*
* @return
* The 32-bit value read from the MSC_READCTRL register.
******************************************************************************/
__STATIC_INLINE uint32_t MSC_ReadCTRLGet(void)
{
#if defined(SL_CATALOG_TZ_SECURE_KEY_LIBRARY_NS_PRESENT)
return sli_tz_ns_interface_dispatch_simple_noarg(
(sli_tz_veneer_simple_noarg_fn)sli_tz_s_interface_dispatch_simple_no_args,
SLI_TZ_MSC_GET_READCTRL_SID);
#else
return MSC->READCTRL;
#endif
}
/***************************************************************************//**
* @brief
* Write a value to the read control register (MSC_READCTRL).
*
* @param[in] value
* The 32-bit value to write to the MSC_READCTRL register.
******************************************************************************/
__STATIC_INLINE void MSC_ReadCTRLSet(uint32_t value)
{
#if defined(SL_CATALOG_TZ_SECURE_KEY_LIBRARY_NS_PRESENT)
(void)sli_tz_ns_interface_dispatch_simple(
(sli_tz_veneer_simple_fn)sli_tz_s_interface_dispatch_simple,
SLI_TZ_MSC_SET_READCTRL_SID,
value);
#else
MSC->READCTRL = value;
#endif
}
#if defined(_MSC_PAGELOCK0_MASK) || defined(_MSC_INST_PAGELOCKWORD0_MASK)
/***************************************************************************//**
* @brief
* Set the lockbit for a flash page in order to prevent page writes/erases to
* the corresponding page.
*
* @param[in] page_number
* The index of the page to apply the pagelock to. Must be in the range
* [0, (flash_size / page_size) - 1].
******************************************************************************/
__STATIC_INLINE void MSC_PageLockSetLocked(uint32_t page_number)
{
#if defined(SL_CATALOG_TZ_SECURE_KEY_LIBRARY_NS_PRESENT)
(void)sli_tz_ns_interface_dispatch_simple(
(sli_tz_veneer_simple_fn)sli_tz_s_interface_dispatch_simple,
SLI_TZ_MSC_SET_PAGELOCK_SID,
page_number);
#else
EFM_ASSERT(page_number < (FLASH_SIZE / FLASH_PAGE_SIZE));
#if defined(_MSC_PAGELOCK0_MASK)
uint32_t *pagelock_registers = (uint32_t *)&MSC->PAGELOCK0;
#elif defined(_MSC_INST_PAGELOCKWORD0_MASK)
uint32_t *pagelock_registers = (uint32_t *)&MSC->INST_PAGELOCKWORD0;
#endif
pagelock_registers[page_number / 32] |= (1 << (page_number % 32));
#endif
}
/***************************************************************************//**
* @brief
* Get the value of the lockbit for a flash page.
*
* @param[in] page_number
* The index of the page to get the lockbit value from. Must be in the range
* [0, (flash_size / page_size) - 1].
*
* @return
* Boolean true if the page is locked, false otherwise.
******************************************************************************/
__STATIC_INLINE bool MSC_PageLockGetLocked(uint32_t page_number)
{
#if defined(SL_CATALOG_TZ_SECURE_KEY_LIBRARY_NS_PRESENT)
return (bool)sli_tz_ns_interface_dispatch_simple(
(sli_tz_veneer_simple_fn)sli_tz_s_interface_dispatch_simple,
SLI_TZ_MSC_GET_PAGELOCK_SID,
page_number);
#else
EFM_ASSERT(page_number < (FLASH_SIZE / FLASH_PAGE_SIZE));
#if defined(_MSC_PAGELOCK0_MASK)
uint32_t *pagelock_registers = (uint32_t *)&MSC->PAGELOCK0;
#elif defined(_MSC_INST_PAGELOCKWORD0_MASK)
uint32_t *pagelock_registers = (uint32_t *)&MSC->INST_PAGELOCKWORD0;
#endif
return pagelock_registers[page_number / 32] & (1 << (page_number % 32));
#endif
}
#endif // _MSC_PAGELOCK0_MASK || _MSC_INST_PAGELOCKWORD0_MASK
#if defined(_MSC_USERDATASIZE_MASK)
/***************************************************************************//**
* @brief
* Get the size of the user data region in flash.
*
* @return
* The size of the user data region divided by 256.
******************************************************************************/
__STATIC_INLINE uint32_t MSC_UserDataGetSize(void)
{
#if defined(SL_CATALOG_TZ_SECURE_KEY_LIBRARY_NS_PRESENT)
return sli_tz_ns_interface_dispatch_simple_noarg(
(sli_tz_veneer_simple_noarg_fn)sli_tz_s_interface_dispatch_simple_no_args,
SLI_TZ_MSC_GET_USERDATA_SIZE_SID);
#else
return MSC->USERDATASIZE;
#endif
}
#endif // _MSC_USERDATASIZE_MASK
#if defined(_MSC_MISCLOCKWORD_MASK)
/***************************************************************************//**
* @brief
* Get the current value of the mass erase and user data page lock word
* (MSC_MISCLOCKWORD).
*
* @return
* The 32-bit value read from the MSC_MISCLOCKWORD register.
******************************************************************************/
__STATIC_INLINE uint32_t MSC_MiscLockWordGet(void)
{
#if defined(SL_CATALOG_TZ_SECURE_KEY_LIBRARY_NS_PRESENT)
return sli_tz_ns_interface_dispatch_simple_noarg(
(sli_tz_veneer_simple_noarg_fn)sli_tz_s_interface_dispatch_simple_no_args,
SLI_TZ_MSC_GET_MISCLOCKWORD_SID);
#else
return MSC->MISCLOCKWORD;
#endif
}
/***************************************************************************//**
* @brief
* Write a value to the mass erase and user data page lock word
* (MSC_MISCLOCKWORD).
*
* @param[in] value
* The 32-bit value to write to the MSC_MISCLOCKWORD register.
******************************************************************************/
__STATIC_INLINE void MSC_MiscLockWordSet(uint32_t value)
{
#if defined(SL_CATALOG_TZ_SECURE_KEY_LIBRARY_NS_PRESENT)
(void)sli_tz_ns_interface_dispatch_simple(
(sli_tz_veneer_simple_fn)sli_tz_s_interface_dispatch_simple,
SLI_TZ_MSC_SET_MISCLOCKWORD_SID,
value);
#else
MSC->MISCLOCKWORD = value;
#endif
}
#endif // _MSC_USERDATASIZE_MASK
#if !defined(SL_CATALOG_TZ_SECURE_KEY_LIBRARY_NS_PRESENT)
/***************************************************************************//**
* @brief
* Clear one or more pending MSC interrupts.
*
* @param[in] flags
* Pending MSC interrupt source to clear. Use a bitwise logic OR combination
* of valid interrupt flags for the MSC module (MSC_IF_nnn).
******************************************************************************/
__STATIC_INLINE void MSC_IntClear(uint32_t flags)
{
#if defined(MSC_HAS_SET_CLEAR)
MSC->IF_CLR = flags;
#else
MSC->IFC = flags;
#endif
}
/***************************************************************************//**
* @brief
* Disable one or more MSC interrupts.
*
* @param[in] flags
* MSC interrupt sources to disable. Use a bitwise logic OR combination of
* valid interrupt flags for the MSC module (MSC_IF_nnn).
******************************************************************************/
__STATIC_INLINE void MSC_IntDisable(uint32_t flags)
{
#if defined(MSC_HAS_SET_CLEAR)
MSC->IEN_CLR = flags;
#else
MSC->IEN &= ~(flags);
#endif
}
/***************************************************************************//**
* @brief
* Enable one or more MSC interrupts.
*
* @note
* Depending on the use, a pending interrupt may already be set prior to
* enabling the interrupt. To ignore a pending interrupt, consider using
* MSC_IntClear() prior to enabling the interrupt.
*
* @param[in] flags
* MSC interrupt sources to enable. Use a bitwise logic OR combination of
* valid interrupt flags for the MSC module (MSC_IF_nnn).
******************************************************************************/
__STATIC_INLINE void MSC_IntEnable(uint32_t flags)
{
#if defined(MSC_HAS_SET_CLEAR)
MSC->IEN_SET = flags;
#else
MSC->IEN |= flags;
#endif
}
/***************************************************************************//**
* @brief
* Get pending MSC interrupt flags.
*
* @note
* The event bits are not cleared by the use of this function.
*
* @return
* MSC interrupt sources pending. A bitwise logic OR combination of valid
* interrupt flags for the MSC module (MSC_IF_nnn).
******************************************************************************/
__STATIC_INLINE uint32_t MSC_IntGet(void)
{
return MSC->IF;
}
/***************************************************************************//**
* @brief
* Get enabled and pending MSC interrupt flags.
* Useful for handling more interrupt sources in the same interrupt handler.
*
* @note
* Interrupt flags are not cleared by the use of this function.
*
* @return
* Pending and enabled MSC interrupt sources.
* The return value is the bitwise AND of
* - the enabled interrupt sources in MSC_IEN and
* - the pending interrupt flags MSC_IF
******************************************************************************/
__STATIC_INLINE uint32_t MSC_IntGetEnabled(void)
{
uint32_t ien;
ien = MSC->IEN;
return MSC->IF & ien;
}
/***************************************************************************//**
* @brief
* Set one or more pending MSC interrupts from SW.
*
* @param[in] flags
* MSC interrupt sources to set to pending. Use a bitwise logic OR combination of
* valid interrupt flags for the MSC module (MSC_IF_nnn).
******************************************************************************/
__STATIC_INLINE void MSC_IntSet(uint32_t flags)
{
#if defined(MSC_HAS_SET_CLEAR)
MSC->IF_SET = flags;
#else
MSC->IFS = flags;
#endif
}
#if defined(MSC_IF_CHOF) && defined(MSC_IF_CMOF)
/***************************************************************************//**
* @brief
* Start measuring the cache hit ratio.
* @details
* Starts performance counters. It is defined inline to
* minimize the impact of this code on the measurement itself.
******************************************************************************/
__STATIC_INLINE void MSC_StartCacheMeasurement(void)
{
/* Clear CMOF and CHOF to catch these later. */
MSC->IFC = MSC_IF_CHOF | MSC_IF_CMOF;
/* Start performance counters. */
#if defined(_MSC_CACHECMD_MASK)
MSC->CACHECMD = MSC_CACHECMD_STARTPC;
#else
MSC->CMD = MSC_CMD_STARTPC;
#endif
}
/***************************************************************************//**
* @brief
* Stop measuring the hit rate.
* @note
* Defined inline to minimize the impact of this
* code on the measurement itself.
* Only works for relatively short sections of code.
* To measure longer sections of code, implement an IRQ Handler for
* the CHOF and CMOF overflow interrupts. These overflows need to be
* counted and included in the total.
* Functions can then be implemented as follows:
* @verbatim
* volatile uint32_t hitOverflows
* volatile uint32_t missOverflows
*
* void MSC_IRQHandler(void)
* {
* uint32_t flags;
* flags = MSC->IF;
* if (flags & MSC_IF_CHOF) {
* MSC->IFC = MSC_IF_CHOF;
* hitOverflows++;
* }
* if (flags & MSC_IF_CMOF) {
* MSC->IFC = MSC_IF_CMOF;
* missOverflows++;
* }
* }
*
* void startPerformanceCounters(void)
* {
* hitOverflows = 0;
* missOverflows = 0;
*
* MSC_IntEnable(MSC_IF_CHOF | MSC_IF_CMOF);
* NVIC_EnableIRQ(MSC_IRQn);
*
* MSC_StartCacheMeasurement();
* }
* @endverbatim
* @return
* Returns -1 if there has been no cache accesses.
* Returns -2 if there has been an overflow in the performance counters.
* If not, it will return the percentage of hits versus misses.
******************************************************************************/
__STATIC_INLINE int32_t MSC_GetCacheMeasurement(void)
{
int32_t total;
int32_t hits;
/* Stop counter before computing hit-rate. */
#if defined(_MSC_CACHECMD_MASK)
MSC->CACHECMD = MSC_CACHECMD_STOPPC;
#else
MSC->CMD = MSC_CMD_STOPPC;
#endif
/* Check for overflows in performance counters. */
if (MSC->IF & (MSC_IF_CHOF | MSC_IF_CMOF)) {
return -2;
}
hits = (int32_t)MSC->CACHEHITS;
total = (int32_t)MSC->CACHEMISSES + hits;
/* To avoid a division by zero. */
if (total == 0) {
return -1;
}
return (hits * 100) / total;
}
/***************************************************************************//**
* @brief
* Flush contents of instruction cache.
******************************************************************************/
__STATIC_INLINE void MSC_FlushCache(void)
{
#if defined(_MSC_CACHECMD_MASK)
MSC->CACHECMD = MSC_CACHECMD_INVCACHE;
#else
MSC->CMD = MSC_CMD_INVCACHE;
#endif
}
/***************************************************************************//**
* @brief
* Enable or disable instruction cache functionality.
* @param[in] enable
* Enable instruction cache. Default is on.
******************************************************************************/
__STATIC_INLINE void MSC_EnableCache(bool enable)
{
BUS_RegBitWrite(&(MSC->READCTRL), _MSC_READCTRL_IFCDIS_SHIFT, !enable);
}
#if defined(MSC_READCTRL_ICCDIS)
/***************************************************************************//**
* @brief
* Enable or disable instruction cache functionality in IRQs.
* @param[in] enable
* Enable instruction cache. Default is on.
******************************************************************************/
__STATIC_INLINE void MSC_EnableCacheIRQs(bool enable)
{
BUS_RegBitWrite(&(MSC->READCTRL), _MSC_READCTRL_ICCDIS_SHIFT, !enable);
}
#endif
/***************************************************************************//**
* @brief
* Enable or disable instruction cache flushing when writing to flash.
* @param[in] enable
* Enable automatic cache flushing. Default is on.
******************************************************************************/
__STATIC_INLINE void MSC_EnableAutoCacheFlush(bool enable)
{
BUS_RegBitWrite(&(MSC->READCTRL), _MSC_READCTRL_AIDIS_SHIFT, !enable);
}
#endif /* defined( MSC_IF_CHOF ) && defined( MSC_IF_CMOF ) */
#if defined(_MSC_READCTRL_BUSSTRATEGY_MASK)
/***************************************************************************//**
* @brief
* Configure which unit should get priority on system bus.
* @param[in] mode
* Unit to prioritize bus accesses for.
******************************************************************************/
__STATIC_INLINE void MSC_BusStrategy(mscBusStrategy_Typedef mode)
{
MSC->READCTRL = (MSC->READCTRL & ~(_MSC_READCTRL_BUSSTRATEGY_MASK)) | mode;
}
#endif
/*******************************************************************************
************************* PROTOTYPES **************************************
******************************************************************************/
void MSC_ExecConfigSet(MSC_ExecConfig_TypeDef *execConfig);
#if defined(_MSC_ECCCTRL_MASK) \
|| defined(_SYSCFG_DMEM0ECCCTRL_MASK) \
|| defined(_MPAHBRAM_CTRL_MASK)
void MSC_EccConfigSet(MSC_EccConfig_TypeDef *eccConfig);
#endif
#if defined(_SYSCFG_DMEM0PORTMAPSEL_MASK)
void MSC_DmemPortMapSet(MSC_DmemMaster_TypeDef master, uint8_t port);
#endif
#if defined(_MPAHBRAM_CTRL_AHBPORTPRIORITY_MASK)
void MSC_PortSetPriority(MSC_PortPriority_TypeDef portPriority);
MSC_PortPriority_TypeDef MSC_PortGetCurrentPriority(void);
#endif
#if !defined(_SILICON_LABS_32B_SERIES_2)
/* Note that this function is deprecated because we no longer support
* placing msc code in ram. */
MSC_RAMFUNC_DECLARATOR
MSC_Status_TypeDef MSC_WriteWordFast(uint32_t *address,
void const *data,
uint32_t numBytes);
#endif
#if defined(MSC_WRITECMD_ERASEMAIN0)
/***************************************************************************//**
* @brief
* Erase the entire Flash in one operation.
*
* @note
* This command will erase the entire contents of the device.
* Use with care, both a debug session and all contents of the flash will be
* lost. The lock bit, MLW will prevent this operation from executing and
* might prevent a successful mass erase.
*
* @return
* Returns the status of the operation.
******************************************************************************/
SL_RAMFUNC_DECLARATOR
MSC_Status_TypeDef MSC_MassErase(void);
#endif
#endif /* !SL_CATALOG_TZ_SECURE_KEY_LIBRARY_NS_PRESENT */
MSC_RAMFUNC_DECLARATOR
MSC_Status_TypeDef MSC_ErasePage(uint32_t *startAddress);
MSC_RAMFUNC_DECLARATOR
MSC_Status_TypeDef MSC_WriteWord(uint32_t *address,
void const *data,
uint32_t numBytes);
#if (_SILICON_LABS_32B_SERIES > 0)
MSC_Status_TypeDef MSC_WriteWordDma(int ch,
uint32_t *address,
const void *data,
uint32_t numBytes);
#endif
void MSC_Init(void);
void MSC_Deinit(void);
/** @} (end addtogroup msc) */
#ifdef __cplusplus
}
#endif
#endif /* defined(MSC_COUNT) && (MSC_COUNT > 0) */
#endif /* EM_MSC_H */

View File

@@ -0,0 +1,81 @@
/***************************************************************************//**
* @file
* @brief Flash Controller (MSC) Compatibility Header
*******************************************************************************
* # License
* <b>Copyright 2018 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* 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.
*
******************************************************************************/
#ifndef EM_MSC_COMPAT_H
#define EM_MSC_COMPAT_H
#if defined(_SILICON_LABS_32B_SERIES_2_CONFIG_2)
#define MSC_IF_PWROFFIF MSC_IF_PWROFF
#define _MSC_IF_PWROFFIF_SHIFT _MSC_IF_PWROFF_SHIFT
#define _MSC_IF_PWROFFIF_MASK _MSC_IF_PWROFF_MASK
#define _MSC_IF_PWROFFIF_DEFAULT _MSC_IF_PWROFF_DEFAULT
#define MSC_IF_PWROFFIF_DEFAULT MSC_IF_PWROFF_DEFAULT
#define MSC_IEN_PWROFFIEN MSC_IEN_PWROFF
#define _MSC_IEN_PWROFFIEN_SHIFT _MSC_IEN_PWROFF_SHIFT
#define _MSC_IEN_PWROFFIEN_MASK _MSC_IEN_PWROFF_MASK
#define _MSC_IEN_PWROFFIEN_DEFAULT _MSC_IEN_PWROFF_DEFAULT
#define MSC_IEN_PWROFFIEN_DEFAULT MSC_IEN_PWROFF_DEFAULT
#define ICACHE_IEN_RAMERRORIEN ICACHE_IEN_RAMERROR
#define _ICACHE_IEN_RAMERRORIEN_SHIFT _ICACHE_IEN_RAMERROR_SHIFT
#define _ICACHE_IEN_RAMERRORIEN_MASK _ICACHE_IEN_RAMERROR_MASK
#define _ICACHE_IEN_RAMERRORIEN_DEFAULT _ICACHE_IEN_RAMERROR_DEFAULT
#define ICACHE_IEN_RAMERRORIEN_DEFAULT ICACHE_IEN_RAMERROR_DEFAULT
#define SYSCFG_IF_FRCRAMERR1BIF SYSCFG_IF_FRCRAMERR1B
#define _SYSCFG_IF_FRCRAMERR1BIF_SHIFT _SYSCFG_IF_FRCRAMERR1B_SHIFT
#define _SYSCFG_IF_FRCRAMERR1BIF_MASK _SYSCFG_IF_FRCRAMERR1B_MASK
#define _SYSCFG_IF_FRCRAMERR1BIF_DEFAULT _SYSCFG_IF_FRCRAMERR1B_DEFAULT
#define SYSCFG_IF_FRCRAMERR1BIF_DEFAULT SYSCFG_IF_FRCRAMERR1B_DEFAULT
#define SYSCFG_IF_FRCRAMERR2BIF SYSCFG_IF_FRCRAMERR2B
#define _SYSCFG_IF_FRCRAMERR2BIF_SHIFT _SYSCFG_IF_FRCRAMERR2B_SHIFT
#define _SYSCFG_IF_FRCRAMERR2BIF_MASK _SYSCFG_IF_FRCRAMERR2B_MASK
#define _SYSCFG_IF_FRCRAMERR2BIF_DEFAULT _SYSCFG_IF_FRCRAMERR2B_DEFAULT
#define SYSCFG_IF_FRCRAMERR2BIF_DEFAULT SYSCFG_IF_FRCRAMERR2B_DEFAULT
#define SYSCFG_IEN_FRCRAMERR1BIEN SYSCFG_IEN_FRCRAMERR1B
#define _SYSCFG_IEN_FRCRAMERR1BIEN_SHIFT _SYSCFG_IEN_FRCRAMERR1B_SHIFT
#define _SYSCFG_IEN_FRCRAMERR1BIEN_MASK _SYSCFG_IEN_FRCRAMERR1B_MASK
#define _SYSCFG_IEN_FRCRAMERR1BIEN_DEFAULT _SYSCFG_IEN_FRCRAMERR1B_DEFAULT
#define SYSCFG_IEN_FRCRAMERR1BIEN_DEFAULT SYSCFG_IEN_FRCRAMERR1B_DEFAULT
#define SYSCFG_IEN_FRCRAMERR2BIEN SYSCFG_IEN_FRCRAMERR2B
#define _SYSCFG_IEN_FRCRAMERR2BIEN_SHIFT _SYSCFG_IEN_FRCRAMERR2B_SHIFT
#define _SYSCFG_IEN_FRCRAMERR2BIEN_MASK _SYSCFG_IEN_FRCRAMERR2B_MASK
#define _SYSCFG_IEN_FRCRAMERR2BIEN_DEFAULT _SYSCFG_IEN_FRCRAMERR2B_DEFAULT
#define SYSCFG_IEN_FRCRAMERR2BIEN_DEFAULT SYSCFG_IEN_FRCRAMERR2B_DEFAULT
#endif /* _SILICON_LABS_32B_SERIES_2_CONFIG_2 */
#endif /* EM_MSC_COMPAT_H */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,905 @@
/***************************************************************************//**
* @file
* @brief Pulse Counter (PCNT) peripheral API
*******************************************************************************
* # License
* <b>Copyright 2018 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* 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.
*
******************************************************************************/
#ifndef EM_PCNT_H
#define EM_PCNT_H
#include "em_device.h"
#if defined(PCNT_COUNT) && (PCNT_COUNT > 0)
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
/***************************************************************************//**
* @addtogroup pcnt
* @{
******************************************************************************/
/*******************************************************************************
******************************* DEFINES ***********************************
******************************************************************************/
/** PCNT0 Counter register size. */
#if defined(_EFM32_GECKO_FAMILY)
#define PCNT0_CNT_SIZE (8) /**< PCNT0 counter is 8 bits. */
#else
#define PCNT0_CNT_SIZE (16) /**< PCNT0 counter is 16 bits. */
#endif
#ifdef PCNT1
/** PCNT1 Counter register size. */
#if defined(_SILICON_LABS_32B_SERIES_0)
#define PCNT1_CNT_SIZE (8) /**< PCNT1 counter is 8 bits. */
#else
#define PCNT1_CNT_SIZE (16) /**< PCNT1 counter is 16 bits. */
#endif
#endif
#ifdef PCNT2
/** PCNT2 Counter register size. */
#if defined(_SILICON_LABS_32B_SERIES_0)
#define PCNT2_CNT_SIZE (8) /**< PCNT2 counter is 8 bits. */
#else
#define PCNT2_CNT_SIZE (16) /**< PCNT2 counter is 16 bits. */
#endif
#endif
/* Define values that can be used in case some state/mode are not defined for some devices.*/
/** PCNT mode disable. */
#define PCNT_MODE_DISABLE 0xFF
/** PCNT count event is none. */
#define PCNT_CNT_EVENT_NONE 0xFF
/*******************************************************************************
******************************** ENUMS ************************************
******************************************************************************/
/** Mode selection. */
#if defined(_SILICON_LABS_32B_SERIES_0) || defined(_SILICON_LABS_32B_SERIES_1)
typedef enum {
/** Disable pulse counter. */
pcntModeDisable = _PCNT_CTRL_MODE_DISABLE,
/** Single input LFACLK oversampling mode (available in EM0-EM2). */
pcntModeOvsSingle = _PCNT_CTRL_MODE_OVSSINGLE,
/** Externally clocked single input counter mode (available in EM0-EM3). */
pcntModeExtSingle = _PCNT_CTRL_MODE_EXTCLKSINGLE,
/** Externally clocked quadrature decoder mode (available in EM0-EM3). */
pcntModeExtQuad = _PCNT_CTRL_MODE_EXTCLKQUAD,
#if defined(_PCNT_CTRL_MODE_OVSQUAD1X)
/** LFACLK oversampling quadrature decoder 1X mode (available in EM0-EM2). */
pcntModeOvsQuad1 = _PCNT_CTRL_MODE_OVSQUAD1X,
/** LFACLK oversampling quadrature decoder 2X mode (available in EM0-EM2). */
pcntModeOvsQuad2 = _PCNT_CTRL_MODE_OVSQUAD2X,
/** LFACLK oversampling quadrature decoder 4X mode (available in EM0-EM2). */
pcntModeOvsQuad4 = _PCNT_CTRL_MODE_OVSQUAD4X,
#endif
} PCNT_Mode_TypeDef;
#else
typedef enum {
/** Disable pulse counter. */
pcntModeDisable = PCNT_MODE_DISABLE,
/** Single input LFACLK oversampling mode (available in EM0-EM2). */
pcntModeOvsSingle = _PCNT_CFG_MODE_OVSSINGLE,
/** Externally clocked single input counter mode (available in EM0-EM3). */
pcntModeExtSingle = _PCNT_CFG_MODE_EXTCLKSINGLE,
/** Externally clocked quadrature decoder mode (available in EM0-EM3). */
pcntModeExtQuad = _PCNT_CFG_MODE_EXTCLKQUAD,
/** LFACLK oversampling quadrature decoder 1X mode (available in EM0-EM2). */
pcntModeOvsQuad1 = _PCNT_CFG_MODE_OVSQUAD1X,
/** LFACLK oversampling quadrature decoder 2X mode (available in EM0-EM2). */
pcntModeOvsQuad2 = _PCNT_CFG_MODE_OVSQUAD2X,
/** LFACLK oversampling quadrature decoder 4X mode (available in EM0-EM2). */
pcntModeOvsQuad4 = _PCNT_CFG_MODE_OVSQUAD4X,
} PCNT_Mode_TypeDef;
#endif
#if defined(_PCNT_CTRL_CNTEV_MASK)
/** Counter event selection.
* Note: unshifted values are being used for enumeration because multiple
* configuration structure members use this type definition. */
typedef enum {
/** Counts up on up-count and down on down-count events. */
pcntCntEventBoth = _PCNT_CTRL_CNTEV_BOTH,
/** Only counts up on up-count events. */
pcntCntEventUp = _PCNT_CTRL_CNTEV_UP,
/** Only counts down on down-count events. */
pcntCntEventDown = _PCNT_CTRL_CNTEV_DOWN,
/** Never counts. */
#if defined(_SILICON_LABS_32B_SERIES_0) || defined(_SILICON_LABS_32B_SERIES_1)
pcntCntEventNone = _PCNT_CTRL_CNTEV_NONE
#else
pcntCntEventNone = PCNT_CNT_EVENT_NONE
#endif
} PCNT_CntEvent_TypeDef;
#endif
/** PRS sources for @p s0PRS and @p s1PRS. */
#if defined(_PCNT_INPUT_MASK)
typedef enum {
pcntPRSCh0 = 0, /**< PRS channel 0. */
pcntPRSCh1 = 1, /**< PRS channel 1. */
pcntPRSCh2 = 2, /**< PRS channel 2. */
pcntPRSCh3 = 3, /**< PRS channel 3. */
#if defined(PCNT_INPUT_S0PRSSEL_PRSCH4)
pcntPRSCh4 = 4, /**< PRS channel 4. */
#endif
#if defined(PCNT_INPUT_S0PRSSEL_PRSCH5)
pcntPRSCh5 = 5, /**< PRS channel 5. */
#endif
#if defined(PCNT_INPUT_S0PRSSEL_PRSCH6)
pcntPRSCh6 = 6, /**< PRS channel 6. */
#endif
#if defined(PCNT_INPUT_S0PRSSEL_PRSCH7)
pcntPRSCh7 = 7, /**< PRS channel 7. */
#endif
#if defined(PCNT_INPUT_S0PRSSEL_PRSCH8)
pcntPRSCh8 = 8, /**< PRS channel 8. */
#endif
#if defined(PCNT_INPUT_S0PRSSEL_PRSCH9)
pcntPRSCh9 = 9, /**< PRS channel 9. */
#endif
#if defined(PCNT_INPUT_S0PRSSEL_PRSCH10)
pcntPRSCh10 = 10, /**< PRS channel 10. */
#endif
#if defined(PCNT_INPUT_S0PRSSEL_PRSCH11)
pcntPRSCh11 = 11, /**< PRS channel 11. */
#endif
#if defined(PCNT_INPUT_S0PRSSEL_PRSCH12)
pcntPRSCh12 = 12, /**< PRS channel 12. */
#endif
#if defined(PCNT_INPUT_S0PRSSEL_PRSCH13)
pcntPRSCh13 = 13, /**< PRS channel 13. */
#endif
#if defined(PCNT_INPUT_S0PRSSEL_PRSCH14)
pcntPRSCh14 = 14, /**< PRS channel 14. */
#endif
#if defined(PCNT_INPUT_S0PRSSEL_PRSCH15)
pcntPRSCh15 = 15, /**< PRS channel 15. */
#endif
#if defined(PCNT_INPUT_S0PRSSEL_PRSCH16)
pcntPRSCh16 = 16, /**< PRS channel 16. */
#endif
#if defined(PCNT_INPUT_S0PRSSEL_PRSCH17)
pcntPRSCh17 = 17, /**< PRS channel 17. */
#endif
#if defined(PCNT_INPUT_S0PRSSEL_PRSCH18)
pcntPRSCh18 = 18, /**< PRS channel 18. */
#endif
#if defined(PCNT_INPUT_S0PRSSEL_PRSCH19)
pcntPRSCh19 = 19, /**< PRS channel 19. */
#endif
#if defined(PCNT_INPUT_S0PRSSEL_PRSCH20)
pcntPRSCh20 = 20, /**< PRS channel 20. */
#endif
#if defined(PCNT_INPUT_S0PRSSEL_PRSCH21)
pcntPRSCh21 = 21, /**< PRS channel 21. */
#endif
#if defined(PCNT_INPUT_S0PRSSEL_PRSCH22)
pcntPRSCh22 = 22, /**< PRS channel 22. */
#endif
#if defined(PCNT_INPUT_S0PRSSEL_PRSCH23)
pcntPRSCh23 = 23, /**< PRS channel 23. */
#endif
} PCNT_PRSSel_TypeDef;
#elif defined(_SILICON_LABS_32B_SERIES_2)
typedef unsigned int PCNT_PRSSel_TypeDef;
#endif
#if defined(_PCNT_INPUT_MASK) || defined(_SILICON_LABS_32B_SERIES_2)
/** PRS inputs of PCNT. */
typedef enum {
pcntPRSInputS0 = 0, /** PRS input 0. */
pcntPRSInputS1 = 1 /** PRS input 1. */
} PCNT_PRSInput_TypeDef;
#endif
/*******************************************************************************
******************************* STRUCTS ***********************************
******************************************************************************/
/** Initialization structure. */
typedef struct {
/** Mode to operate in. */
PCNT_Mode_TypeDef mode;
/** Initial counter value (refer to reference manual for max value allowed).
* Only used for #pcntModeOvsSingle (and possibly #pcntModeDisable) modes.
* If using #pcntModeExtSingle or #pcntModeExtQuad modes, counter
* value is reset to HW reset value. */
uint32_t counter;
/** Initial top value (refer to reference manual for max value allowed).
* Only used for #pcntModeOvsSingle (and possibly #pcntModeDisable) modes.
* If using #pcntModeExtSingle or #pcntModeExtQuad modes, top
* value is reset to HW reset value. */
uint32_t top;
/** Polarity of incoming edge.
* @li #pcntModeExtSingle mode - if false, positive edges are counted,
* otherwise negative edges.
* @li #pcntModeExtQuad mode - if true, counting direction is inverted. */
bool negEdge;
/** Counting direction, only applicable for #pcntModeOvsSingle and
* #pcntModeExtSingle modes. */
bool countDown;
/** Enable filter, only available in #pcntModeOvsSingle* mode. */
bool filter;
#if defined(_SILICON_LABS_32B_SERIES_2)
/** Enable/disable PCNT counting during debug halt. Only in OVSSINGLE and OVSQUAD modes. */
bool debugHalt;
#endif
#if defined(PCNT_CTRL_HYST) || defined(_SILICON_LABS_32B_SERIES_2)
/** Set to true to enable hysteresis. When enabled, PCNT will always
* overflow and underflow to TOP/2. */
bool hyst;
#endif
#if defined(PCNT_CTRL_S1CDIR)
/** Set to true to enable S1 to determine the direction of counting in
* OVSSINGLE or EXTCLKSINGLE modes. @n
* When S1 is high, the count direction is given by CNTDIR, and when S1 is
* low, the count direction is the opposite. */
bool s1CntDir;
#endif
#if defined(_PCNT_CTRL_CNTEV_SHIFT)
/** Selects whether the regular counter responds to up-count events,
* down-count events, both, or none. */
PCNT_CntEvent_TypeDef cntEvent;
#endif
#if defined(_PCNT_CTRL_AUXCNTEV_SHIFT)
/** Selects whether the auxiliary counter responds to up-count events,
* down-count events, both, or none. */
PCNT_CntEvent_TypeDef auxCntEvent;
#endif
#if defined(_PCNT_INPUT_MASK) || defined(_SILICON_LABS_32B_SERIES_2)
/** Select PRS channel as input to S0IN in PCNTx_INPUT register. */
PCNT_PRSSel_TypeDef s0PRS;
/** Select PRS channel as input to S1IN in PCNTx_INPUT register. */
PCNT_PRSSel_TypeDef s1PRS;
#endif
} PCNT_Init_TypeDef;
/** Default Debug. */
#if defined(_SILICON_LABS_32B_SERIES_2)
#define DEFAULT_DEBUG_HALT true,
#else
#define DEFAULT_DEBUG_HALT
#endif
/** Default Mode. */
#define DEFAULT_MODE pcntModeDisable, /**< Disabled by default. */
/** Default Hysteresis. */
#if defined(PCNT_CTRL_HYST) || defined(_SILICON_LABS_32B_SERIES_2)
#define DEFAULT_HYST false, /**< Hysteresis disabled. */
#else
#define DEFAULT_HYST
#endif
/** Default counter direction*/
#if defined(PCNT_CTRL_S1CDIR)
#define DEFAULT_CDIR true, /**< Counter direction is given by CNTDIR. */
#else
#define DEFAULT_CDIR
#endif
/** Default count event*/
#if defined(_PCNT_CTRL_CNTEV_SHIFT)
#define DEFAULT_CNTEV pcntCntEventUp, /**< Regular counter counts up on upcount events. */
#else
#define DEFAULT_CNTEV
#endif
/** Default auxiliary count event. */
#if defined(_PCNT_CTRL_AUXCNTEV_SHIFT)
#define DEFAULT_AUXCNTEV pcntCntEventNone, /**< Auxiliary counter doesn't respond to events. */
#else
#define DEFAULT_AUXCNTEV
#endif
/** Default selected PRS channel as S0IN and S1IN. */
#if defined(_PCNT_INPUT_MASK)
#define DEFAULT_PRS_CH pcntPRSCh0, /**< PRS channel 0 selected as S0IN and as S1IN. */
#elif defined(_SILICON_LABS_32B_SERIES_2)
#define DEFAULT_PRS_CH 0u,
#else
#define DEFAULT_PRS_CH
#endif
/** Default configuration for PCNT initialization structure. */
#define PCNT_INIT_DEFAULT \
{ \
DEFAULT_MODE /* Default mode. */ \
_PCNT_CNT_RESETVALUE, /* Default counter HW reset value. */ \
_PCNT_TOP_RESETVALUE, /* Default counter HW reset value. */ \
false, /* Use positive edge. */ \
false, /* Up-counting. */ \
false, /* Filter disabled. */ \
DEFAULT_DEBUG_HALT /* Debug Halt enabled. */ \
DEFAULT_HYST /* Default Hysteresis. */ \
DEFAULT_CDIR /* Default CNTDIR. */ \
DEFAULT_CNTEV /* Faults CNTEV. */ \
DEFAULT_AUXCNTEV /* Default AUXCNTEV. */ \
DEFAULT_PRS_CH /* PRS channel 0 selected as S0IN. */ \
DEFAULT_PRS_CH /* PRS channel 0 selected as S1IN. */ \
}
#if defined(PCNT_OVSCFG_FILTLEN_DEFAULT) || defined(_SILICON_LABS_32B_SERIES_2)
/** Filter initialization structure */
typedef struct {
/** Used only in OVSINGLE and OVSQUAD1X-4X modes. To use this, enable filter by
* setting filter to true during PCNT_Init(). Filter length = (filtLen + 5) LFACLK cycles. */
uint8_t filtLen;
/** When set, removes flutter from Quaddecoder inputs S0IN and S1IN.
* Available only in OVSQUAD1X-4X modes. */
bool flutterrm;
} PCNT_Filter_TypeDef;
#endif
/** Default configuration for PCNT initialization structure. */
#if defined(PCNT_OVSCFG_FILTLEN_DEFAULT) || defined(_SILICON_LABS_32B_SERIES_2)
#define PCNT_FILTER_DEFAULT \
{ \
0, /* Default length is 5 LFACLK cycles. */ \
false /* No flutter removal. */ \
}
#endif
#if defined(PCNT_CTRL_TCCMODE_DEFAULT)
/** Modes for Triggered Compare and Clear module. */
typedef enum {
/** Triggered compare and clear not enabled. */
tccModeDisabled = _PCNT_CTRL_TCCMODE_DISABLED,
/** Compare and clear performed on each (optionally prescaled) LFA clock cycle. */
tccModeLFA = _PCNT_CTRL_TCCMODE_LFA,
/** Compare and clear performed on PRS edges. Polarity defined by prsPolarity. */
tccModePRS = _PCNT_CTRL_TCCMODE_PRS
} PCNT_TCCMode_TypeDef;
/** Prescaler values for LFA compare and clear events. Only has effect when TCC mode is LFA. */
typedef enum {
/** Compare and clear event each LFA cycle. */
tccPrescDiv1 = _PCNT_CTRL_TCCPRESC_DIV1,
/** Compare and clear event every other LFA cycle. */
tccPrescDiv2 = _PCNT_CTRL_TCCPRESC_DIV2,
/** Compare and clear event every 4th LFA cycle. */
tccPrescDiv4 = _PCNT_CTRL_TCCPRESC_DIV4,
/** Compare and clear event every 8th LFA cycle. */
tccPrescDiv8 = _PCNT_CTRL_TCCPRESC_DIV8
} PCNT_TCCPresc_Typedef;
/** Compare modes for TCC module. */
typedef enum {
/** Compare match if PCNT_CNT is less than, or equal to PCNT_TOP. */
tccCompLTOE = _PCNT_CTRL_TCCCOMP_LTOE,
/** Compare match if PCNT_CNT is greater than or equal to PCNT_TOP. */
tccCompGTOE = _PCNT_CTRL_TCCCOMP_GTOE,
/** Compare match if PCNT_CNT is less than, or equal to PCNT_TOP[15:8]], and greater
* than, or equal to PCNT_TOP[7:0]. */
tccCompRange = _PCNT_CTRL_TCCCOMP_RANGE
} PCNT_TCCComp_Typedef;
/** TCC initialization structure. */
typedef struct {
/** Mode to operate in. */
PCNT_TCCMode_TypeDef mode;
/** Prescaler value for LFACLK in LFA mode. */
PCNT_TCCPresc_Typedef prescaler;
/** Choose the event that will trigger a clear. */
PCNT_TCCComp_Typedef compare;
/** PRS input to TCC module, either for gating the PCNT clock, triggering the TCC comparison, or both. */
PCNT_PRSSel_TypeDef tccPRS;
/** TCC PRS input polarity. @n
* False = Rising edge for comparison trigger, and PCNT clock gated when PRS signal is high. @n
* True = Falling edge for comparison trigger, and PCNT clock gated when PRS signal is low. */
bool prsPolarity;
/** Enable gating PCNT input clock through TCC PRS signal.
* Polarity selection is done through prsPolarity. */
bool prsGateEnable;
} PCNT_TCC_TypeDef;
/** TCC Default. */
#define PCNT_TCC_DEFAULT \
{ \
tccModeDisabled, /* Disabled by default. */ \
tccPrescDiv1, /* Do not prescale LFA clock in LFA mode. */ \
tccCompLTOE, /* Clear when CNT <= TOP. */ \
pcntPRSCh0, /* Select PRS channel 0 as input to TCC. */ \
false, /* PRS polarity is rising edge, and gate when 1. */ \
false /* Do not gate PCNT counter input. */ \
}
#endif
/* defined(PCNT_CTRL_TCCMODE_DEFAULT) */
/*******************************************************************************
***************************** PROTOTYPES **********************************
******************************************************************************/
/***************************************************************************//**
* @brief
* Get the pulse counter value.
*
* @param[in] pcnt
* Pointer to the PCNT peripheral register block.
*
* @return
* Current pulse counter value.
******************************************************************************/
__STATIC_INLINE uint32_t PCNT_CounterGet(PCNT_TypeDef *pcnt)
{
return pcnt->CNT;
}
#if defined(_PCNT_AUXCNT_MASK)
/***************************************************************************//**
* @brief
* Get the auxiliary counter value.
*
* @param[in] pcnt
* Pointer to the PCNT peripheral register block.
*
* @return
* Current auxiliary counter value.
******************************************************************************/
__STATIC_INLINE uint32_t PCNT_AuxCounterGet(PCNT_TypeDef *pcnt)
{
return pcnt->AUXCNT;
}
#endif
void PCNT_CounterReset(PCNT_TypeDef *pcnt);
void PCNT_CounterTopSet(PCNT_TypeDef *pcnt, uint32_t count, uint32_t top);
/***************************************************************************//**
* @brief
* Set a counter value.
*
* @details
* Pulse counter is disabled while changing counter value and re-enabled
* (if originally enabled) when counter value has been set.
*
* @note
* This function will stall until synchronization to low-frequency domain is
* completed. For that reason, it should normally not be used when using
* an external clock to clock the PCNT module since stall time may be
* undefined in that case. The counter should normally only be set when
* operating in (or about to enable) #pcntModeOvsSingle mode.
*
* @param[in] pcnt
* Pointer to the PCNT peripheral register block.
*
* @param[in] count
* Value to set in counter register.
******************************************************************************/
__STATIC_INLINE void PCNT_CounterSet(PCNT_TypeDef *pcnt, uint32_t count)
{
PCNT_CounterTopSet(pcnt, count, pcnt->TOP);
}
void PCNT_Enable(PCNT_TypeDef *pcnt, PCNT_Mode_TypeDef mode);
bool PCNT_IsEnabled(PCNT_TypeDef *pcnt);
#if defined(_SILICON_LABS_32B_SERIES_0) || defined(_SILICON_LABS_32B_SERIES_1)
void PCNT_FreezeEnable(PCNT_TypeDef *pcnt, bool enable);
#endif
void PCNT_Init(PCNT_TypeDef *pcnt, const PCNT_Init_TypeDef *init);
#if defined(PCNT_OVSCFG_FILTLEN_DEFAULT) || defined(_SILICON_LABS_32B_SERIES_2)
void PCNT_FilterConfiguration(PCNT_TypeDef *pcnt, const PCNT_Filter_TypeDef *config, bool enable);
#endif
#if defined(_PCNT_INPUT_MASK) || defined(_SILICON_LABS_32B_SERIES_2)
void PCNT_PRSInputEnable(PCNT_TypeDef *pcnt,
PCNT_PRSInput_TypeDef prsInput,
bool enable);
#endif
#if defined(PCNT_CTRL_TCCMODE_DEFAULT)
void PCNT_TCCConfiguration(PCNT_TypeDef *pcnt, const PCNT_TCC_TypeDef *config);
#endif
/***************************************************************************//**
* @brief
* Clear one or more pending PCNT interrupts.
*
* @param[in] pcnt
* Pointer to the PCNT peripheral register block.
*
* @param[in] flags
* Pending PCNT interrupt source to clear. Use a bitwise logic OR combination
* of valid interrupt flags for the PCNT module (PCNT_IF_nnn).
******************************************************************************/
__STATIC_INLINE void PCNT_IntClear(PCNT_TypeDef *pcnt, uint32_t flags)
{
#if defined(_SILICON_LABS_32B_SERIES_0) || defined(_SILICON_LABS_32B_SERIES_1)
pcnt->IFC = flags;
#else
pcnt->IF_CLR = flags;
#endif
}
/***************************************************************************//**
* @brief
* Disable one or more PCNT interrupts.
*
* @param[in] pcnt
* Pointer to the PCNT peripheral register block.
*
* @param[in] flags
* PCNT interrupt sources to disable. Use a bitwise logic OR combination of
* valid interrupt flags for PCNT module (PCNT_IF_nnn).
******************************************************************************/
__STATIC_INLINE void PCNT_IntDisable(PCNT_TypeDef *pcnt, uint32_t flags)
{
#if defined(PCNT_HAS_SET_CLEAR)
pcnt->IEN_CLR = flags;
#else
pcnt->IEN &= ~flags;
#endif
}
/***************************************************************************//**
* @brief
* Enable one or more PCNT interrupts.
*
* @note
* Depending on the use, a pending interrupt may already be set prior to
* enabling the interrupt. To ignore a pending interrupt, consider using
* PCNT_IntClear() prior to enabling the interrupt.
*
* @param[in] pcnt
* Pointer to the PCNT peripheral register block.
*
* @param[in] flags
* PCNT interrupt sources to enable. Use a bitwise logic OR combination of
* valid interrupt flags for PCNT module (PCNT_IF_nnn).
******************************************************************************/
__STATIC_INLINE void PCNT_IntEnable(PCNT_TypeDef *pcnt, uint32_t flags)
{
#if defined(PCNT_HAS_SET_CLEAR)
pcnt->IEN_SET = flags;
#else
pcnt->IEN |= flags;
#endif
}
/***************************************************************************//**
* @brief
* Get pending PCNT interrupt flags.
*
* @note
* The event bits are not cleared by the use of this function.
*
* @param[in] pcnt
* Pointer to the PCNT peripheral register block.
*
* @return
* PCNT interrupt sources pending. A bitwise logic OR combination of valid
* interrupt flags for PCNT module (PCNT_IF_nnn).
******************************************************************************/
__STATIC_INLINE uint32_t PCNT_IntGet(PCNT_TypeDef *pcnt)
{
return pcnt->IF;
}
/***************************************************************************//**
* @brief
* Get enabled and pending PCNT interrupt flags.
*
* @details
* Useful for handling more interrupt sources in the same interrupt handler.
*
* @note
* The event bits are not cleared by the use of this function.
*
* @param[in] pcnt
* Pointer to thePCNT peripheral register block.
*
* @return
* Pending and enabled PCNT interrupt sources.
* The return value is the bitwise AND combination of
* - the OR combination of enabled interrupt sources in PCNT_IEN_nnn
* register (PCNT_IEN_nnn) and
* - the OR combination of valid interrupt flags of the PCNT module
* (PCNT_IF_nnn).
******************************************************************************/
__STATIC_INLINE uint32_t PCNT_IntGetEnabled(PCNT_TypeDef *pcnt)
{
uint32_t ien;
/* Store pcnt->IEN in temporary variable in order to define explicit order
* of volatile accesses. */
ien = pcnt->IEN;
/* Bitwise AND of pending and enabled interrupts. */
return pcnt->IF & ien;
}
/***************************************************************************//**
* @brief
* Set one or more pending PCNT interrupts from SW.
*
* @param[in] pcnt
* Pointer to the PCNT peripheral register block.
*
* @param[in] flags
* PCNT interrupt sources to set to pending. Use a bitwise logic OR combination
* of valid interrupt flags for PCNT module (PCNT_IF_nnn).
******************************************************************************/
__STATIC_INLINE void PCNT_IntSet(PCNT_TypeDef *pcnt, uint32_t flags)
{
#if defined(_SILICON_LABS_32B_SERIES_0) || defined(_SILICON_LABS_32B_SERIES_1)
pcnt->IFS = flags;
#else
pcnt->IF_SET = flags;
#endif
}
#if defined(_PCNT_LOCK_MASK)
/***************************************************************************//**
* @brief
* Lock PCNT registers.
*
* @param[in] pcnt
* Pointer to the PCNT peripheral register block.
*
* @note When PCNT registers are locked PCNT_CFG, PCNT_EN, PCNT_SWRST, PCNT_CMD,
* PCNT_CTRL, PCNT_OVSCTRL, PCNT_CNT, PCNT_TOP, and PCNT_TOPB registers
* cannot be written to.
******************************************************************************/
__STATIC_INLINE void PCNT_Lock(PCNT_TypeDef *pcnt)
{
pcnt->LOCK = ~PCNT_LOCK_PCNTLOCKKEY_UNLOCK;
}
#endif
#if defined(_PCNT_LOCK_MASK)
/***************************************************************************//**
* @brief
* Unlock PCNT registers.
*
* @param[in] pcnt
* Pointer to thePCNT peripheral register block.
******************************************************************************/
__STATIC_INLINE void PCNT_Unlock(PCNT_TypeDef *pcnt)
{
pcnt->LOCK = PCNT_LOCK_PCNTLOCKKEY_UNLOCK;
}
#endif
void PCNT_Reset(PCNT_TypeDef *pcnt);
/***************************************************************************//**
* @brief
* Get the pulse counter top buffer value.
*
* @param[in] pcnt
* Pointer to the PCNT peripheral register block.
*
* @return
* Current pulse counter top buffer value.
******************************************************************************/
__STATIC_INLINE uint32_t PCNT_TopBufferGet(PCNT_TypeDef *pcnt)
{
#if defined(_SILICON_LABS_32B_SERIES_2)
while (pcnt->SYNCBUSY & PCNT_SYNCBUSY_TOPB) {
}
#endif
return pcnt->TOPB;
}
void PCNT_TopBufferSet(PCNT_TypeDef *pcnt, uint32_t val);
/***************************************************************************//**
* @brief
* Get the pulse counter top value.
*
* @param[in] pcnt
* Pointer to the PCNT peripheral register block.
*
* @return
* Current pulse counter top value.
******************************************************************************/
__STATIC_INLINE uint32_t PCNT_TopGet(PCNT_TypeDef *pcnt)
{
#if defined(_SILICON_LABS_32B_SERIES_2)
while (pcnt->SYNCBUSY & PCNT_SYNCBUSY_TOP) {
}
#endif
return pcnt->TOP;
}
void PCNT_TopSet(PCNT_TypeDef *pcnt, uint32_t val);
/***************************************************************************//**
* @brief
* Wait for an ongoing sync of register(s) to low-frequency domain to complete.
*
* @param[in] pcnt
* A pointer to the PCNT peripheral register block.
*
* @param[in] mask
* A bitmask corresponding to SYNCBUSY register defined bits indicating
* registers that must complete any ongoing synchronization.
******************************************************************************/
__STATIC_INLINE void PCNT_Sync(PCNT_TypeDef *pcnt, uint32_t mask)
{
/* Avoid deadlock if modifying the same register twice when freeze mode is
* activated. */
#if defined(_SILICON_LABS_32B_SERIES_0) || defined(_SILICON_LABS_32B_SERIES_1)
if (pcnt->FREEZE & PCNT_FREEZE_REGFREEZE) {
return;
}
#endif
/* Wait for any pending previous write operation to have been completed in
* low-frequency domain. */
while (pcnt->SYNCBUSY & mask) {
}
}
#if defined(_SILICON_LABS_32B_SERIES_2)
/***************************************************************************//**
* @brief
* Start the main PCNT counter.
*
* @details
* This function will send a start command to the PCNT peripheral. The PCNT
* peripheral will use some LF clock ticks before the command is executed.
* The @ref PCNT_Sync() function can be used to wait for the start command
* to be executed.
*
* @param[in] pcnt
* A pointer to the PCNT peripheral register block.
*
* @note
* This function requires the PCNT to be enabled.
******************************************************************************/
__STATIC_INLINE void PCNT_StartMainCnt(PCNT_TypeDef *pcnt)
{
PCNT_Sync(pcnt, PCNT_SYNCBUSY_CMD);
pcnt->CMD_SET = PCNT_CMD_STARTCNT;
}
/***************************************************************************//**
* @brief
* Stop the main PCNT counter.
*
* @details
* This function will send a stop command to the PCNT peripheral. The PCNT
* peripheral will use some LF clock ticks before the command is executed.
* The @ref PCNT_Sync() function can be used to wait for the stop command
* to be executed.
*
* @param[in] pcnt
* A pointer to the PCNT peripheral register block.
*
* @note
* This function requires the PCNT to be enabled.
******************************************************************************/
__STATIC_INLINE void PCNT_StopMainCnt(PCNT_TypeDef *pcnt)
{
PCNT_Sync(pcnt, PCNT_SYNCBUSY_CMD);
pcnt->CMD_SET = PCNT_CMD_STOPCNT;
}
/***************************************************************************//**
* @brief
* Start the auxiliary PCNT counter.
*
* @details
* This function will send a start command to the PCNT peripheral. The PCNT
* peripheral will use some LF clock ticks before the command is executed.
* The @ref PCNT_Sync() function can be used to wait for the start command
* to be executed.
*
* @param[in] pcnt
* A pointer to the PCNT peripheral register block.
*
* @note
* This function requires the PCNT to be enabled.
******************************************************************************/
__STATIC_INLINE void PCNT_StartAuxCnt(PCNT_TypeDef *pcnt)
{
PCNT_Sync(pcnt, PCNT_SYNCBUSY_CMD);
pcnt->CMD_SET = PCNT_CMD_STARTAUXCNT;
}
/***************************************************************************//**
* @brief
* Stop the auxiliary PCNT counter.
*
* @details
* This function will send a stop command to the PCNT peripheral. The PCNT
* peripheral will use some LF clock ticks before the command is executed.
* The @ref PCNT_Sync() function can be used to wait for the stop command
* to be executed.
*
* @param[in] pcnt
* A pointer to the PCNT peripheral register block.
*
* @note
* This function requires the PCNT to be enabled.
******************************************************************************/
__STATIC_INLINE void PCNT_StopAuxCnt(PCNT_TypeDef *pcnt)
{
PCNT_Sync(pcnt, PCNT_SYNCBUSY_CMD);
pcnt->CMD_SET = PCNT_CMD_STOPAUXCNT;
}
#endif
/** @} (end addtogroup pcnt) */
#ifdef __cplusplus
}
#endif
#endif /* defined(PCNT_COUNT) && (PCNT_COUNT > 0) */
#endif /* EM_PCNT_H */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,169 @@
/***************************************************************************//**
* @file
* @brief RAM code support.
*******************************************************************************
* # License
* <b>Copyright 2018 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* 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.
*
******************************************************************************/
#ifndef EM_RAMFUNC_H
#define EM_RAMFUNC_H
#include "sl_code_classification.h"
#ifdef __cplusplus
extern "C" {
#endif
/* *INDENT-OFF* */
/***************************************************************************//**
* @addtogroup ramfunc RAMFUNC - RAM Function Support
* @brief RAM code support
* @details
* Provides support for executing code from RAM.
* Provides a unified method to manage RAM code across all supported tools.
* @{
@note
Other cross-compiler support macros are implemented in [COMMON](../../common/api/group-common).
@note
Functions executing from RAM should not be declared as static.
@warning
Standard library facilities are available to the tool with GCC in hosted
mode (default), regardless of the section attribute. Calls to standard
libraries placed in the default section may therefore occur. To disable
hosted mode, add '-ffreestanding' to the build command line. This is the
only way to guarantee no calls to standard libraries with GCC.
Read more at www.gcc.gnu.org/onlinedocs/gcc-5.3.0/gcc/Standards.html
@warning
Keil/ARM uVision users must add a section named "ram_code" in their linker
scatter file. This section must be in RAM memory. Look in the MCU SDK for
example scatter files (ram_code.sct).
@n @section ramfunc_usage Usage
In your .h file:
@verbatim
#include "em_ramfunc.h"
SL_RAMFUNC_DECLARATOR
void MyPrint(const char* string);
@endverbatim
Issues have been observed with ARM GCC when there is no declarator. It is
recommended to have a declarator also for internal functions but move the
declarator to the .c file.
In your .c file:
@verbatim
#include "em_ramfunc.h"
SL_RAMFUNC_DEFINITION_BEGIN
void MyPrint(const char* string)
{
...
}
SL_RAMFUNC_DEFINITION_END
@endverbatim
******************************************************************************/
/* *INDENT-ON* */
/*******************************************************************************
****************************** DEFINES ***********************************
******************************************************************************/
/**
* @brief
* This define is not present by default. By compiling with define
* @ref SL_RAMFUNC_DISABLE, code placed in RAM by SL_RAMFUNC macros
* will be placed in default code space (Flash) instead.
*
* @note
* This define is not present by default.
*/
#if defined(DOXY_DOC_ONLY)
#define SL_RAMFUNC_DISABLE
#endif
#if defined(SL_RAMFUNC_DISABLE)
/** @brief Compiler ported function declarator for RAM code. */
#define SL_RAMFUNC_DECLARATOR
/** @brief Compiler ported function definition begin marker for RAM code. */
#define SL_RAMFUNC_DEFINITION_BEGIN
/** @brief Compiler ported function definition end marker for RAM code. */
#define SL_RAMFUNC_DEFINITION_END
#elif defined(__CC_ARM)
/* MDK-ARM compiler */
#define SL_RAMFUNC_DECLARATOR
#define SL_RAMFUNC_DEFINITION_BEGIN _Pragma("arm section code=\"ram_code\"")
#define SL_RAMFUNC_DEFINITION_END _Pragma("arm section code")
#elif defined(__ICCARM__)
/* IAR Embedded Workbench */
#define SL_RAMFUNC_DECLARATOR SL_CODE_RAM
#define SL_RAMFUNC_DEFINITION_BEGIN SL_RAMFUNC_DECLARATOR
#define SL_RAMFUNC_DEFINITION_END
#elif defined(__GNUC__) && (defined(__CROSSWORKS_ARM) || defined(__SES_ARM))
/* Rowley Crossworks and Segger Embedded Studio */
#define SL_RAMFUNC_DECLARATOR SL_CODE_RAM
#define SL_RAMFUNC_DEFINITION_BEGIN SL_RAMFUNC_DECLARATOR
#define SL_RAMFUNC_DEFINITION_END
#elif defined(__GNUC__) && defined(CONFIG_SOC_FAMILY_EXX32)
/* Zephyr environment */
#define SL_RAMFUNC_DECLARATOR SL_CODE_RAM
#define SL_RAMFUNC_DEFINITION_BEGIN SL_RAMFUNC_DECLARATOR
#define SL_RAMFUNC_DEFINITION_END
#elif defined(__GNUC__)
/* Simplicity Studio, Atollic and Vanilla armgcc */
#define SL_RAMFUNC_DECLARATOR SL_CODE_RAM
#define SL_RAMFUNC_DEFINITION_BEGIN SL_RAMFUNC_DECLARATOR
#define SL_RAMFUNC_DEFINITION_END
#endif
/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
/* Deprecated macro names */
#define RAMFUNC_DECLARATOR SL_RAMFUNC_DECLARATOR
#define RAMFUNC_DEFINITION_BEGIN SL_RAMFUNC_DEFINITION_BEGIN
#define RAMFUNC_DEFINITION_END SL_RAMFUNC_DEFINITION_END
/** @endcond */
/** @} (end addtogroup ramfunc) */
#ifdef __cplusplus
}
#endif
#endif /* EM_RAMFUNC_H */

View File

@@ -0,0 +1,178 @@
/***************************************************************************//**
* @file
* @brief Reset Management Unit (RMU) peripheral API
*******************************************************************************
* # License
* <b>Copyright 2018 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* 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.
*
******************************************************************************/
#ifndef EM_RMU_H
#define EM_RMU_H
#include "em_device.h"
#if (defined(RMU_COUNT) && (RMU_COUNT > 0)) || (_EMU_RSTCTRL_MASK)
#include "sl_assert.h"
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
/***************************************************************************//**
* @addtogroup rmu
* @{
******************************************************************************/
/*******************************************************************************
******************************** ENUMS ************************************
******************************************************************************/
/** RMU reset modes. */
typedef enum {
#if defined(_RMU_CTRL_PINRMODE_MASK)
rmuResetModeDisabled = _RMU_CTRL_PINRMODE_DISABLED, /**< Reset mode disabled. */
rmuResetModeLimited = _RMU_CTRL_PINRMODE_LIMITED, /**< Reset mode limited. */
rmuResetModeExtended = _RMU_CTRL_PINRMODE_EXTENDED, /**< Reset mode extended. */
rmuResetModeFull = _RMU_CTRL_PINRMODE_FULL, /**< Reset mode full. */
#elif defined(_EMU_RSTCTRL_MASK)
rmuResetModeDisabled = 0, /**< Reset mode disabled. */
rmuResetModeEnabled = 1, /**< Reset mode enabled. */
#else
rmuResetModeClear = 0, /**< Reset mode clear. */
rmuResetModeSet = 1, /**< Reset mode set. */
#endif
} RMU_ResetMode_TypeDef;
/** RMU controlled peripheral reset control and reset source control. */
typedef enum {
#if defined(RMU_CTRL_BURSTEN)
rmuResetBU = _RMU_CTRL_BURSTEN_MASK, /**< Reset control over Backup Power domain select. */
#endif
#if defined(RMU_CTRL_LOCKUPRDIS)
rmuResetLockUp = _RMU_CTRL_LOCKUPRDIS_MASK, /**< Cortex lockup reset select. */
#elif defined(_RMU_CTRL_LOCKUPRMODE_MASK)
rmuResetLockUp = _RMU_CTRL_LOCKUPRMODE_MASK, /**< Cortex lockup reset select. */
#endif
#if defined(_RMU_CTRL_WDOGRMODE_MASK)
rmuResetWdog = _RMU_CTRL_WDOGRMODE_MASK, /**< WDOG reset select. */
#endif
#if defined(_RMU_CTRL_LOCKUPRMODE_MASK)
rmuResetCoreLockup = _RMU_CTRL_LOCKUPRMODE_MASK, /**< Cortex lockup reset select. */
#endif
#if defined(_RMU_CTRL_SYSRMODE_MASK)
rmuResetSys = _RMU_CTRL_SYSRMODE_MASK, /**< SYSRESET select. */
#endif
#if defined(_RMU_CTRL_PINRMODE_MASK)
rmuResetPin = _RMU_CTRL_PINRMODE_MASK, /**< Pin reset select. */
#endif
#if defined(_EMU_RSTCTRL_WDOG0RMODE_MASK)
rmuResetWdog0 = _EMU_RSTCTRL_WDOG0RMODE_MASK, /**< WDOG0 reset select */
#endif
#if defined(_EMU_RSTCTRL_WDOG1RMODE_MASK)
rmuResetWdog1 = _EMU_RSTCTRL_WDOG1RMODE_MASK, /**< WDOG1 reset select */
#endif
#if defined(_EMU_RSTCTRL_SYSRMODE_MASK)
rmuResetSys = _EMU_RSTCTRL_SYSRMODE_MASK, /**< SYSRESET select */
#endif
#if defined(_EMU_RSTCTRL_LOCKUPRMODE_MASK)
rmuResetCoreLockup = _EMU_RSTCTRL_LOCKUPRMODE_MASK, /**< Cortex lockup reset select */
#endif
#if defined(_EMU_RSTCTRL_AVDDBODRMODE_MASK)
rmuResetAVDD = _EMU_RSTCTRL_AVDDBODRMODE_MASK, /**< AVDD monitoring select */
#endif
#if defined(_EMU_RSTCTRL_IOVDD0BODRMODE_MASK)
rmuResetIOVDD0 = _EMU_RSTCTRL_IOVDD0BODRMODE_MASK, /**< IOVDD0 monitoring select */
#endif
#if defined(_EMU_RSTCTRL_IOVDD1BODRMODE_MASK)
rmuResetIOVDD1 = _EMU_RSTCTRL_IOVDD1BODRMODE_MASK, /**< IOVDD1 monitoring select */
#endif
#if defined(_EMU_RSTCTRL_IOVDD2BODRMODE_MASK)
rmuResetIOVDD2 = _EMU_RSTCTRL_IOVDD2BODRMODE_MASK, /**< IOVDD2 monitoring select */
#endif
#if defined(_EMU_RSTCTRL_DECBODRMODE_MASK)
rmuResetDecouple = _EMU_RSTCTRL_DECBODRMODE_MASK, /**< Decouple monitoring select */
#endif
#if defined(_EMU_RSTCTRL_SESYSRMODE_MASK)
rmuResetSESys = _EMU_RSTCTRL_SESYSRMODE_MASK, /**< M0+ (SE) system reset select */
#endif
#if defined(_EMU_RSTCTRL_SELOCKUPRMODE_MASK)
rmuResetSELockup = _EMU_RSTCTRL_SELOCKUPRMODE_MASK, /**< M0+ (SE) lockup select */
#endif
#if defined(_EMU_RSTCTRL_DCIRMODE_MASK)
rmuResetDCI = _EMU_RSTCTRL_DCIRMODE_MASK, /**< DCI reset select */
#endif
} RMU_Reset_TypeDef;
/*******************************************************************************
***************************** PROTOTYPES **********************************
******************************************************************************/
/** RMU_LockupResetDisable kept for backwards compatibility. */
#define RMU_LockupResetDisable(A) RMU_ResetControl(rmuResetLockUp, A)
void RMU_ResetControl(RMU_Reset_TypeDef reset, RMU_ResetMode_TypeDef mode);
void RMU_ResetCauseClear(void);
uint32_t RMU_ResetCauseGet(void);
#if defined(_RMU_CTRL_RESETSTATE_MASK)
/***************************************************************************//**
* @brief
* Set user reset state. Reset only by a Power-on-reset and a pin reset.
*
* @param[in] userState User state to set
******************************************************************************/
__STATIC_INLINE void RMU_UserResetStateSet(uint32_t userState)
{
EFM_ASSERT(!(userState
& ~(_RMU_CTRL_RESETSTATE_MASK >> _RMU_CTRL_RESETSTATE_SHIFT)));
RMU->CTRL = (RMU->CTRL & ~_RMU_CTRL_RESETSTATE_MASK)
| (userState << _RMU_CTRL_RESETSTATE_SHIFT);
}
/***************************************************************************//**
* @brief
* Get user reset state. Reset only by a Power-on-reset and a pin reset.
*
* @return
* Reset surviving user state.
******************************************************************************/
__STATIC_INLINE uint32_t RMU_UserResetStateGet(void)
{
uint32_t userState = (RMU->CTRL & _RMU_CTRL_RESETSTATE_MASK)
>> _RMU_CTRL_RESETSTATE_SHIFT;
return userState;
}
#endif
/** @} (end addtogroup rmu) */
#ifdef __cplusplus
}
#endif
#endif /* defined(RMU_COUNT) && (RMU_COUNT > 0) */
#endif /* EM_RMU_H */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,174 @@
/***************************************************************************//**
* @file
* @brief API defining acces to SYSCFG registers
*******************************************************************************
* # License
* <b>Copyright 2022 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* 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.
*
******************************************************************************/
#ifndef EM_SYSCFG_H
#define EM_SYSCFG_H
#include "em_device.h"
#if defined(SL_TRUSTZONE_NONSECURE)
#include "sli_tz_service_syscfg.h"
#endif
#ifdef __cplusplus
extern "C" {
#endif
#if defined(SYSCFG)
/*******************************************************************************
******************************** TZ SERVICES **********************************
******************************************************************************/
#if defined(_SYSCFG_CHIPREV_FAMILY_MASK) || defined(_SYSCFG_CHIPREV_PARTNUMBER_MASK)
/*******************************************************************************
* @brief Reads CHIPREV register
******************************************************************************/
__STATIC_INLINE uint32_t SYSCFG_readChipRev(void)
{
#if defined(SL_TRUSTZONE_NONSECURE)
return sli_tz_syscfg_read_chiprev_register();
#else
#if defined(CMU_CLKEN0_SYSCFG)
CMU->CLKEN0_SET = CMU_CLKEN0_SYSCFG;
#endif
return SYSCFG->CHIPREV;
#endif
}
#endif // defined(_SYSCFG_CHIPREV_FAMILY_MASK) || defined(_SYSCFG_CHIPREV_PARTNUMBER_MASK)
#if defined(_SYSCFG_DMEM0RAMCTRL_RAMWSEN_MASK)
/*******************************************************************************
* @brief Sets DMEM0RAMCTRL RAMWSEN bit to 1
******************************************************************************/
__STATIC_INLINE void SYSCFG_setDmem0RamCtrlRamwsenBit(void)
{
#if defined(SL_TRUSTZONE_NONSECURE)
sli_tz_syscfg_set_dmem0ramctrl_ramwsen_bit();
#else
SYSCFG->DMEM0RAMCTRL = SYSCFG->DMEM0RAMCTRL | _SYSCFG_DMEM0RAMCTRL_RAMWSEN_MASK;
#endif
}
/*******************************************************************************
* @brief Clears DMEM0RAMCTRL RAMWSEN bit to 0
******************************************************************************/
__STATIC_INLINE void SYSCFG_clearDmem0RamCtrlRamwsenBit(void)
{
#if defined(SL_TRUSTZONE_NONSECURE)
sli_tz_syscfg_clear_dmem0ramctrl_ramwsen_bit();
#else
SYSCFG->DMEM0RAMCTRL = SYSCFG->DMEM0RAMCTRL & ~_SYSCFG_DMEM0RAMCTRL_RAMWSEN_MASK;
#endif
}
/*******************************************************************************
* @brief Reads DMEM0RAMCTRL RAMWSEN bit
******************************************************************************/
__STATIC_INLINE uint32_t SYSCFG_getDmem0RamCtrlRamwsenBit(void)
{
#if defined(SL_TRUSTZONE_NONSECURE)
return sli_tz_syscfg_get_dmem0ramctrl_ramwsen_bit();
#else
return (SYSCFG->DMEM0RAMCTRL & _SYSCFG_DMEM0RAMCTRL_RAMWSEN_MASK) >> _SYSCFG_DMEM0RAMCTRL_RAMWSEN_SHIFT;
#endif
}
#endif //_SYSCFG_DMEM0RAMCTRL_RAMWSEN_MASK
#if defined(_SYSCFG_DMEM0RETNCTRL_MASK)
/*******************************************************************************
* @brief Reads DMEM0RETNCTRL register
******************************************************************************/
__STATIC_INLINE uint32_t SYSCFG_readDmem0RetnCtrl(void)
{
#if defined(SL_TRUSTZONE_NONSECURE)
return sli_tz_syscfg_read_dmem0retnctrl_register();
#else
return SYSCFG->DMEM0RETNCTRL;
#endif
}
/*******************************************************************************
* @brief Mask DMEM0RETNCTRL register with provided mask
*
* @param mask - A mask that is to be used to mask the DMEM0RETNCTRL register
******************************************************************************/
__STATIC_INLINE void SYSCFG_maskDmem0RetnCtrl(uint32_t mask)
{
#if defined(SL_TRUSTZONE_NONSECURE)
sli_tz_syscfg_mask_dmem0retnctrl_register(mask);
#else
SYSCFG->DMEM0RETNCTRL = SYSCFG->DMEM0RETNCTRL | mask;
#endif
}
/*******************************************************************************
* @brief Set DMEM0RETNCTRL to zero
******************************************************************************/
__STATIC_INLINE void SYSCFG_zeroDmem0RetnCtrl(void)
{
#if defined(SL_TRUSTZONE_NONSECURE)
sli_tz_syscfg_zero_dmem0retnctrl_register();
#else
SYSCFG->DMEM0RETNCTRL = 0x0UL;
#endif
}
#endif // _SYSCFG_DMEM0RETNCTRL_MASK
#if defined(_SYSCFG_CFGSYSTIC_MASK)
/*******************************************************************************
* @brief Set SYSTICEXTCLKEN bit in CFGSYSTIC to one
******************************************************************************/
__STATIC_INLINE void SYSCFG_setSysTicExtClkEnCfgSysTic(void)
{
#if defined(SL_TRUSTZONE_NONSECURE)
sli_tz_syscfg_set_systicextclken_cfgsystic();
#else
SYSCFG->CFGSYSTIC = (SYSCFG->CFGSYSTIC | _SYSCFG_CFGSYSTIC_SYSTICEXTCLKEN_MASK);
#endif
}
/*******************************************************************************
* @brief Clear SYSTICEXTCLKEN bit in CFGSYSTIC to zero
******************************************************************************/
__STATIC_INLINE void SYSCFG_clearSysTicExtClkEnCfgSysTic(void)
{
#if defined(SL_TRUSTZONE_NONSECURE)
sli_tz_syscfg_clear_systicextclken_cfgsystic();
#else
SYSCFG->CFGSYSTIC = (SYSCFG->CFGSYSTIC & ~_SYSCFG_CFGSYSTIC_SYSTICEXTCLKEN_MASK);
#endif
}
#endif //_SYSCFG_CFGSYSTIC_MASK
#endif //SYSCFG
#ifdef __cplusplus
}
#endif
#endif // EM_SYSCFG_H

View File

@@ -0,0 +1,365 @@
/***************************************************************************//**
* @file
* @brief System API
*******************************************************************************
* # License
* <b>Copyright 2018 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* 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.
*
******************************************************************************/
#ifndef EM_SYSTEM_H
#define EM_SYSTEM_H
#include "em_device.h"
#include "em_system_generic.h"
#ifdef __cplusplus
extern "C" {
#endif
/***************************************************************************//**
* @addtogroup system SYSTEM - System Utils
* @brief System API
* @details
* This module contains functions to read information such as RAM and Flash size,
* device unique ID, chip revision, family, and part number from DEVINFO and
* SCB blocks. Functions to configure and read status from FPU are available for
* compatible devices.
* @{
******************************************************************************/
/*******************************************************************************
******************************** ENUMS ************************************
******************************************************************************/
/** Family identifiers. */
typedef enum {
/* New style family #defines */
#if defined(_DEVINFO_PART_DEVICE_FAMILY_EFM32G)
systemPartFamilyEfm32Gecko = _DEVINFO_PART_DEVICE_FAMILY_EFM32G, /**< EFM32 Gecko Device Family. */
#endif
#if defined(_DEVINFO_PART_DEVICE_FAMILY_EFM32GG)
systemPartFamilyEfm32Giant = _DEVINFO_PART_DEVICE_FAMILY_EFM32GG, /**< EFM32 Giant Gecko Series 0 Device Family. */
#endif
#if defined(_DEVINFO_PART_DEVICE_FAMILY_EFM32GG11B)
systemPartFamilyEfm32Giant11B = _DEVINFO_PART_DEVICE_FAMILY_EFM32GG11B, /**< EFM32 Giant Gecko Series 1 Configuration 1 Basic Device Family. */
#endif
#if defined(_DEVINFO_PART_DEVICE_FAMILY_EFM32GG12B)
systemPartFamilyEfm32Giant12B = _DEVINFO_PART_DEVICE_FAMILY_EFM32GG12B, /**< EFM32 Giant Gecko Series 1 Configuration 2 Basic Device Family. */
#endif
#if defined(_DEVINFO_PART_DEVICE_FAMILY_EFM32TG)
systemPartFamilyEfm32Tiny = _DEVINFO_PART_DEVICE_FAMILY_EFM32TG, /**< EFM32 Tiny Gecko Device Family. */
#endif
#if defined(_DEVINFO_PART_DEVICE_FAMILY_EFM32TG11B)
systemPartFamilyEfm32Tiny11B = _DEVINFO_PART_DEVICE_FAMILY_EFM32TG11B, /**< EFM32 Tiny Gecko 11 Device Family. */
#endif
#if defined(_DEVINFO_PART_DEVICE_FAMILY_EFM32LG)
systemPartFamilyEfm32Leopard = _DEVINFO_PART_DEVICE_FAMILY_EFM32LG, /**< EFM32 Leopard Gecko Device Family. */
#endif
#if defined(_DEVINFO_PART_DEVICE_FAMILY_EFM32WG)
systemPartFamilyEfm32Wonder = _DEVINFO_PART_DEVICE_FAMILY_EFM32WG, /**< EFM32 Wonder Gecko Device Family. */
#endif
#if defined(_DEVINFO_PART_DEVICE_FAMILY_EFM32ZG)
systemPartFamilyEfm32Zero = _DEVINFO_PART_DEVICE_FAMILY_EFM32ZG, /**< EFM32 Zero Gecko Device Family. */
#endif
#if defined(_DEVINFO_PART_DEVICE_FAMILY_EFM32HG)
systemPartFamilyEfm32Happy = _DEVINFO_PART_DEVICE_FAMILY_EFM32HG, /**< EFM32 Happy Gecko Device Family. */
#endif
#if defined(_DEVINFO_PART_DEVICE_FAMILY_EFM32PG1B)
systemPartFamilyEfm32Pearl1B = _DEVINFO_PART_DEVICE_FAMILY_EFM32PG1B, /**< EFM32 Pearl Gecko Series 1 Configuration 1 Basic Device Family. */
#endif
#if defined(_DEVINFO_PART_DEVICE_FAMILY_EFM32JG1B)
systemPartFamilyEfm32Jade1B = _DEVINFO_PART_DEVICE_FAMILY_EFM32JG1B, /**< EFM32 Jade Gecko Series 1 Configuration 1 Basic Device Family. */
#endif
#if defined(_DEVINFO_PART_DEVICE_FAMILY_EFM32PG12B)
systemPartFamilyEfm32Pearl12B = _DEVINFO_PART_DEVICE_FAMILY_EFM32PG12B, /**< EFM32 Pearl Gecko Series 1 Configuration 2 Basic Device Family. */
#endif
#if defined(_DEVINFO_PART_DEVICE_FAMILY_EFM32JG12B)
systemPartFamilyEfm32Jade12B = _DEVINFO_PART_DEVICE_FAMILY_EFM32JG12B, /**< EFM32 Jade Gecko Series 1 Configuration 2 Basic Device Family. */
#endif
#if defined(_DEVINFO_PART_DEVICE_FAMILY_EZR32WG)
systemPartFamilyEzr32Wonder = _DEVINFO_PART_DEVICE_FAMILY_EZR32WG, /**< EZR32 Wonder Device Family. */
#endif
#if defined(_DEVINFO_PART_DEVICE_FAMILY_EZR32LG)
systemPartFamilyEzr32Leopard = _DEVINFO_PART_DEVICE_FAMILY_EZR32LG, /**< EZR32 Leopard Device Family. */
#endif
#if defined(_DEVINFO_PART_DEVICE_FAMILY_EZR32HG)
systemPartFamilyEzr32Happy = _DEVINFO_PART_DEVICE_FAMILY_EZR32HG, /**< EZR32 Happy Device Family. */
#endif
#if defined(_DEVINFO_PART_DEVICE_FAMILY_EFR32MG1P)
systemPartFamilyMighty1P = _DEVINFO_PART_DEVICE_FAMILY_EFR32MG1P, /**< EFR32 Mighty Gecko Series 1 Configuration 1 Premium Device Family. */
#endif
#if defined(_DEVINFO_PART_DEVICE_FAMILY_EFR32MG1B)
systemPartFamilyMighty1B = _DEVINFO_PART_DEVICE_FAMILY_EFR32MG1B, /**< EFR32 Mighty Gecko Series 1 Configuration 1 Basic Device Family. */
#endif
#if defined(_DEVINFO_PART_DEVICE_FAMILY_EFR32MG1V)
systemPartFamilyMighty1V = _DEVINFO_PART_DEVICE_FAMILY_EFR32MG1V, /**< EFR32 Mighty Gecko Series 1 Configuration 1 Value Device Family. */
#endif
#if defined(_DEVINFO_PART_DEVICE_FAMILY_EFR32BG1P)
systemPartFamilyBlue1P = _DEVINFO_PART_DEVICE_FAMILY_EFR32BG1P, /**< EFR32 Blue Gecko Series 1 Configuration 1 Premium Device Family. */
#endif
#if defined(_DEVINFO_PART_DEVICE_FAMILY_EFR32BG1B)
systemPartFamilyBlue1B = _DEVINFO_PART_DEVICE_FAMILY_EFR32BG1B, /**< EFR32 Blue Gecko Series 1 Configuration 1 Basic Device Family. */
#endif
#if defined(_DEVINFO_PART_DEVICE_FAMILY_EFR32BG1V)
systemPartFamilyBlue1V = _DEVINFO_PART_DEVICE_FAMILY_EFR32BG1V, /**< EFR32 Blue Gecko Series 1 Configuration 1 Value Device Family. */
#endif
#if defined(_DEVINFO_PART_DEVICE_FAMILY_EFR32FG1P)
systemPartFamilyFlex1P = _DEVINFO_PART_DEVICE_FAMILY_EFR32FG1P, /**< EFR32 Flex Gecko Series 1 Configuration 1 Premium Device Family. */
#endif
#if defined(_DEVINFO_PART_DEVICE_FAMILY_EFR32FG1B)
systemPartFamilyFlex1B = _DEVINFO_PART_DEVICE_FAMILY_EFR32FG1B, /**< EFR32 Flex Gecko Series 1 Configuration 1 Basic Device Family. */
#endif
#if defined(_DEVINFO_PART_DEVICE_FAMILY_EFR32FG1V)
systemPartFamilyFlex1V = _DEVINFO_PART_DEVICE_FAMILY_EFR32FG1V, /**< EFR32 Flex Gecko Series 1 Configuration 1 Value Device Family. */
#endif
#if defined(_DEVINFO_PART_DEVICE_FAMILY_EFR32MG12P)
systemPartFamilyMighty12P = _DEVINFO_PART_DEVICE_FAMILY_EFR32MG12P, /**< EFR32 Mighty Gecko Series 1 Configuration 2 Premium Device Family. */
#endif
#if defined(_DEVINFO_PART_DEVICE_FAMILY_EFR32MG12B)
systemPartFamilyMighty12B = _DEVINFO_PART_DEVICE_FAMILY_EFR32MG12B, /**< EFR32 Mighty Gecko Series 1 Configuration 2 Basic Device Family. */
#endif
#if defined(_DEVINFO_PART_DEVICE_FAMILY_EFR32MG12V)
systemPartFamilyMighty12V = _DEVINFO_PART_DEVICE_FAMILY_EFR32MG12V, /**< EFR32 Mighty Gecko Series 1 Configuration 2 Value Device Family. */
#endif
#if defined(_DEVINFO_PART_DEVICE_FAMILY_EFR32BG12P)
systemPartFamilyBlue12P = _DEVINFO_PART_DEVICE_FAMILY_EFR32BG12P, /**< EFR32 Blue Gecko Series 1 Configuration 2 Premium Device Family. */
#endif
#if defined(_DEVINFO_PART_DEVICE_FAMILY_EFR32BG12B)
systemPartFamilyBlue12B = _DEVINFO_PART_DEVICE_FAMILY_EFR32BG12B, /**< EFR32 Blue Gecko Series 1 Configuration 2 Basic Device Family. */
#endif
#if defined(_DEVINFO_PART_DEVICE_FAMILY_EFR32BG12V)
systemPartFamilyBlue12V = _DEVINFO_PART_DEVICE_FAMILY_EFR32BG12V, /**< EFR32 Blue Gecko Series 1 Configuration 2 Value Device Family. */
#endif
#if defined(_DEVINFO_PART_DEVICE_FAMILY_EFR32FG12P)
systemPartFamilyFlex12P = _DEVINFO_PART_DEVICE_FAMILY_EFR32FG12P, /**< EFR32 Flex Gecko Series 1 Configuration 2 Premium Device Family. */
#endif
#if defined(_DEVINFO_PART_DEVICE_FAMILY_EFR32FG12B)
systemPartFamilyFlex12B = _DEVINFO_PART_DEVICE_FAMILY_EFR32FG12B, /**< EFR32 Flex Gecko Series 1 Configuration 2 Basic Device Family. */
#endif
#if defined(_DEVINFO_PART_DEVICE_FAMILY_EFR32FG12V)
systemPartFamilyFlex12V = _DEVINFO_PART_DEVICE_FAMILY_EFR32FG12V, /**< EFR32 Flex Gecko Series 1 Configuration 2 Value Device Family. */
#endif
#if defined(_DEVINFO_PART_DEVICE_FAMILY_EFR32MG13P)
systemPartFamilyMighty13P = _DEVINFO_PART_DEVICE_FAMILY_EFR32MG13P, /**< EFR32 Mighty Gecko Series 1 Configuration 3 Premium Device Family. */
#endif
#if defined(_DEVINFO_PART_DEVICE_FAMILY_EFR32MG13B)
systemPartFamilyMighty13B = _DEVINFO_PART_DEVICE_FAMILY_EFR32MG13B, /**< EFR32 Mighty Gecko Series 1 Configuration 3 Basic Device Family. */
#endif
#if defined(_DEVINFO_PART_DEVICE_FAMILY_EFR32MG13V)
systemPartFamilyMighty13V = _DEVINFO_PART_DEVICE_FAMILY_EFR32MG13V, /**< EFR32 Mighty Gecko Series 1 Configuration 3 Value Device Family. */
#endif
#if defined(_DEVINFO_PART_DEVICE_FAMILY_EFR32BG13P)
systemPartFamilyBlue13P = _DEVINFO_PART_DEVICE_FAMILY_EFR32BG13P, /**< EFR32 Blue Gecko Series 1 Configuration 3 Premium Device Family. */
#endif
#if defined(_DEVINFO_PART_DEVICE_FAMILY_EFR32BG13B)
systemPartFamilyBlue13B = _DEVINFO_PART_DEVICE_FAMILY_EFR32BG13B, /**< EFR32 Blue Gecko Series 1 Configuration 3 Basic Device Family. */
#endif
#if defined(_DEVINFO_PART_DEVICE_FAMILY_EFR32BG13V)
systemPartFamilyBlue13V = _DEVINFO_PART_DEVICE_FAMILY_EFR32BG13V, /**< EFR32 Blue Gecko Series 1 Configuration 3 Value Device Family. */
#endif
#if defined(_DEVINFO_PART_DEVICE_FAMILY_EFR32FG13P)
systemPartFamilyFlex13P = _DEVINFO_PART_DEVICE_FAMILY_EFR32FG13P, /**< EFR32 Flex Gecko Series 1 Configuration 3 Premium Device Family. */
#endif
#if defined(_DEVINFO_PART_DEVICE_FAMILY_EFR32FG13B)
systemPartFamilyFlex13B = _DEVINFO_PART_DEVICE_FAMILY_EFR32FG13B, /**< EFR32 Flex Gecko Series 1 Configuration 3 Basic Device Family. */
#endif
#if defined(_DEVINFO_PART_DEVICE_FAMILY_EFR32FG13V)
systemPartFamilyFlex13V = _DEVINFO_PART_DEVICE_FAMILY_EFR32FG13V, /**< EFR32 Flex Gecko Series 1 Configuration 3 Value Device Family. */
#endif
#if defined(_DEVINFO_PART_DEVICE_FAMILY_EFR32ZG13P)
systemPartFamilyZen13P = _DEVINFO_PART_DEVICE_FAMILY_EFR32ZG13P, /**< EFR32 Zen Gecko Series 1 Configuration 3 Premium Device Family. */
#endif
#if defined(_DEVINFO_PART_DEVICE_FAMILY_EFR32ZG13L)
systemPartFamilyZen13L = _DEVINFO_PART_DEVICE_FAMILY_EFR32ZG13L, /**< EFR32 Zen Gecko Series 1 Configuration 3 Led Device Family. */
#endif
#if defined(_DEVINFO_PART_DEVICE_FAMILY_EFR32ZG13S)
systemPartFamilyZen13S = _DEVINFO_PART_DEVICE_FAMILY_EFR32ZG13S, /**< EFR32 Zen Gecko Series 1 Configuration 3 Sensor Device Family. */
#endif
#if defined(_DEVINFO_PART_DEVICE_FAMILY_EFR32MG14P)
systemPartFamilyMighty14P = _DEVINFO_PART_DEVICE_FAMILY_EFR32MG14P, /**< EFR32 Mighty Gecko Series 1 Configuration 4 Premium Device Family. */
#endif
#if defined(_DEVINFO_PART_DEVICE_FAMILY_EFR32MG14B)
systemPartFamilyMighty14B = _DEVINFO_PART_DEVICE_FAMILY_EFR32MG14B, /**< EFR32 Mighty Gecko Series 1 Configuration 4 Basic Device Family. */
#endif
#if defined(_DEVINFO_PART_DEVICE_FAMILY_EFR32MG14V)
systemPartFamilyMighty14V = _DEVINFO_PART_DEVICE_FAMILY_EFR32MG14V, /**< EFR32 Mighty Gecko Series 1 Configuration 4 Value Device Family. */
#endif
#if defined(_DEVINFO_PART_DEVICE_FAMILY_EFR32FG14P)
systemPartFamilyFlex14P = _DEVINFO_PART_DEVICE_FAMILY_EFR32FG14P, /**< EFR32 Flex Gecko Series 1 Configuration 4 Premium Device Family. */
#endif
#if defined(_DEVINFO_PART_DEVICE_FAMILY_EFR32FG14B)
systemPartFamilyFlex14B = _DEVINFO_PART_DEVICE_FAMILY_EFR32FG14B, /**< EFR32 Flex Gecko Series 1 Configuration 4 Basic Device Family. */
#endif
#if defined(_DEVINFO_PART_DEVICE_FAMILY_EFR32FG14V)
systemPartFamilyFlex14V = _DEVINFO_PART_DEVICE_FAMILY_EFR32FG14V, /**< EFR32 Flex Gecko Series 1 Configuration 4 Value Device Family. */
#endif
#if defined(_DEVINFO_PART_DEVICE_FAMILY_EFR32ZG14P)
systemPartFamilyZen14P = _DEVINFO_PART_DEVICE_FAMILY_EFR32ZG14P, /**< EFR32 Zen Gecko Series 1 Configuration 4 Premium Device Family. */
#endif
#if defined(_SILICON_LABS_32B_SERIES_2_CONFIG_1)
systemPartFamilyMighty21 = DEVINFO_PART_FAMILY_MG | (21 << _DEVINFO_PART_FAMILYNUM_SHIFT), /**< EFR32 Mighty Gecko Series 2 Config 1 Value Device Family */
systemPartFamilyFlex21 = DEVINFO_PART_FAMILY_FG | (21 << _DEVINFO_PART_FAMILYNUM_SHIFT), /**< EFR32 Flex Gecko Series 2 Config 1 Value Device Family */
systemPartFamilyBlue21 = DEVINFO_PART_FAMILY_BG | (21 << _DEVINFO_PART_FAMILYNUM_SHIFT), /**< EFR32 Blue Gecko Series 2 Config 1 Value Device Family */
systemPartFamilyMightyRcp21 = DEVINFO_PART_FAMILY_MR | (21 << _DEVINFO_PART_FAMILYNUM_SHIFT), /**< EFR32 Mighty RCP Series 2 Config 1 Value Device Family */
#endif
#if defined(_SILICON_LABS_32B_SERIES_2_CONFIG_2)
systemPartFamilyMighty22 = DEVINFO_PART_FAMILY_MG | (22 << _DEVINFO_PART_FAMILYNUM_SHIFT), /**< EFR32 Mighty Gecko Series 2 Config 2 Value Device Family */
systemPartFamilyFlex22 = DEVINFO_PART_FAMILY_FG | (22 << _DEVINFO_PART_FAMILYNUM_SHIFT), /**< EFR32 Flex Gecko Series 2 Config 2 Value Device Family */
systemPartFamilyBlue22 = DEVINFO_PART_FAMILY_BG | (22 << _DEVINFO_PART_FAMILYNUM_SHIFT), /**< EFR32 Blue Gecko Series 2 Config 2 Value Device Family */
systemPartFamilyEfm32Pearl22 = DEVINFO_PART_FAMILY_PG | (22 << _DEVINFO_PART_FAMILYNUM_SHIFT), /**< EFM32 Pearl Gecko Series 2 Config 2 Value Device Family */
#endif
#if defined(_SILICON_LABS_32B_SERIES_2_CONFIG_3)
systemPartFamilyFlex23 = DEVINFO_PART_FAMILY_FG | (23 << _DEVINFO_PART_FAMILYNUM_SHIFT), /**< EFR32 Flex Gecko Series 2 Config 3 Value Device Family */
systemPartFamilyZen23 = DEVINFO_PART_FAMILY_ZG | (23 << _DEVINFO_PART_FAMILYNUM_SHIFT), /**< EFR32 Zen Gecko Series 2 Config 3 Value Device Family */
systemPartFamilyEfm32Pearl23 = DEVINFO_PART_FAMILY_PG | (23 << _DEVINFO_PART_FAMILYNUM_SHIFT), /**< EFM32 Pearl Gecko Series 2 Config 3 Value Device Family */
systemPartFamilySideWalk23 = DEVINFO_PART_FAMILY_SG | (23 << _DEVINFO_PART_FAMILYNUM_SHIFT), /**< EFR32 Side Walk Gecko Series 2 Config 3 Value Device Family */
#endif
#if defined(_SILICON_LABS_32B_SERIES_2_CONFIG_4)
systemPartFamilyMighty24 = DEVINFO_PART_FAMILY_MG | (24 << _DEVINFO_PART_FAMILYNUM_SHIFT), /**< EFR32 Mighty Gecko Series 2 Config 4 Value Device Family */
systemPartFamilyFlex24 = DEVINFO_PART_FAMILY_FG | (24 << _DEVINFO_PART_FAMILYNUM_SHIFT), /**< EFR32 Flex Gecko Series 2 Config 4 Value Device Family */
systemPartFamilyBlue24 = DEVINFO_PART_FAMILY_BG | (24 << _DEVINFO_PART_FAMILYNUM_SHIFT), /**< EFR32 Blue Gecko Series 2 Config 4 Value Device Family */
#endif
#if defined(_SILICON_LABS_32B_SERIES_2_CONFIG_5)
systemPartFamilyFlex25 = DEVINFO_PART_FAMILY_FG | (25 << _DEVINFO_PART_FAMILYNUM_SHIFT), /**< EFR32 Flex Gecko Series 2 Config 5 Value Device Family */
#endif
#if defined(_SILICON_LABS_32B_SERIES_2_CONFIG_6)
systemPartFamilyMighty26 = DEVINFO_PART_FAMILY_MG | (26 << _DEVINFO_PART_FAMILYNUM_SHIFT), /**< EFR32 Mighty Gecko Series 2 Config 6 Value Device Family */
systemPartFamilyBlue26 = DEVINFO_PART_FAMILY_BG | (26 << _DEVINFO_PART_FAMILYNUM_SHIFT), /**< EFR32 Blue Gecko Series 2 Config 6 Value Device Family */
systemPartFamilyEfm32Pearl26 = DEVINFO_PART_FAMILY_PG | (26 << _DEVINFO_PART_FAMILYNUM_SHIFT), /**< EFM32 Pearl Gecko Series 2 Config 6 Value Device Family */
#endif
#if defined(_SILICON_LABS_32B_SERIES_2_CONFIG_7)
systemPartFamilyMighty27 = DEVINFO_PART_FAMILY_MG | (27 << _DEVINFO_PART_FAMILYNUM_SHIFT), /**< EFR32 Mighty Gecko Series 2 Config 7 Value Device Family */
systemPartFamilyBlue27 = DEVINFO_PART_FAMILY_BG | (27 << _DEVINFO_PART_FAMILYNUM_SHIFT), /**< EFR32 Blue Gecko Series 2 Config 7 Value Device Family */
#endif
#if defined(_SILICON_LABS_32B_SERIES_2_CONFIG_8)
systemPartFamilyFlex28 = DEVINFO_PART_FAMILY_FG | (28 << _DEVINFO_PART_FAMILYNUM_SHIFT), /**< EFR32 Flex Gecko Series 2 Config 8 Value Device Family */
systemPartFamilyZen28 = DEVINFO_PART_FAMILY_ZG | (28 << _DEVINFO_PART_FAMILYNUM_SHIFT), /**< EFR32 Zen Gecko Series 2 Config 8 Value Device Family */
systemPartFamilySideWalk28 = DEVINFO_PART_FAMILY_SG | (28 << _DEVINFO_PART_FAMILYNUM_SHIFT), /**< EFR32 Side Walk Gecko Series 2 Config 8 Value Device Family */
systemPartFamilyEfm32Pearl28 = DEVINFO_PART_FAMILY_PG | (28 << _DEVINFO_PART_FAMILYNUM_SHIFT), /**< EFM32 Pearl Gecko Series 2 Config 8 Value Device Family */
#endif
#if defined(_SILICON_LABS_32B_SERIES_2_CONFIG_9)
systemPartFamilyMighty29 = DEVINFO_PART_FAMILY_MG | (29 << _DEVINFO_PART_FAMILYNUM_SHIFT), /**< EFR32 Mighty Gecko Series 2 Config 9 Value Device Family */
systemPartFamilyBlue29 = DEVINFO_PART_FAMILY_BG | (29 << _DEVINFO_PART_FAMILYNUM_SHIFT), /**< EFR32 Blue Gecko Series 2 Config 9 Value Device Family */
#endif
/* Deprecated family #defines */
#if defined(_DEVINFO_PART_DEVICE_FAMILY_G)
systemPartFamilyGecko = _DEVINFO_PART_DEVICE_FAMILY_G, /**< Gecko Device Family. */
#endif
#if defined(_DEVINFO_PART_DEVICE_FAMILY_GG)
systemPartFamilyGiant = _DEVINFO_PART_DEVICE_FAMILY_GG, /**< Giant Gecko Device Family. */
#endif
#if defined(_DEVINFO_PART_DEVICE_FAMILY_TG)
systemPartFamilyTiny = _DEVINFO_PART_DEVICE_FAMILY_TG, /**< Tiny Gecko Device Family. */
#endif
#if defined(_DEVINFO_PART_DEVICE_FAMILY_LG)
systemPartFamilyLeopard = _DEVINFO_PART_DEVICE_FAMILY_LG, /**< Leopard Gecko Device Family. */
#endif
#if defined(_DEVINFO_PART_DEVICE_FAMILY_WG)
systemPartFamilyWonder = _DEVINFO_PART_DEVICE_FAMILY_WG, /**< Wonder Gecko Device Family. */
#endif
#if defined(_DEVINFO_PART_DEVICE_FAMILY_ZG)
systemPartFamilyZero = _DEVINFO_PART_DEVICE_FAMILY_ZG, /**< Zero Gecko Device Family. */
#endif
#if defined(_DEVINFO_PART_DEVICE_FAMILY_HG)
systemPartFamilyHappy = _DEVINFO_PART_DEVICE_FAMILY_HG, /**< Happy Gecko Device Family. */
#endif
systemPartFamilyUnknown = 0xFF /**< Unknown Device Family.
Family ID is missing
on unprogrammed parts. */
} SYSTEM_PartFamily_TypeDef;
/*******************************************************************************
******************************* STRUCTS ***********************************
******************************************************************************/
/** Chip revision details. */
typedef struct {
uint8_t minor; /**< Minor revision number. */
uint8_t major; /**< Major revision number. */
#if defined(_SYSCFG_CHIPREV_PARTNUMBER_MASK)
uint16_t partNumber; /**< Device part number. */
#else
uint8_t family; /**< Device family number. */
#endif
} SYSTEM_ChipRevision_TypeDef;
#if defined(__FPU_PRESENT) && (__FPU_PRESENT == 1)
/** Floating point co-processor access modes. */
typedef enum {
fpuAccessDenied = (0x0 << 20), /**< Access denied, any attempted access generates a NOCP UsageFault. */
fpuAccessPrivilegedOnly = (0x5 << 20), /**< Privileged access only, an unprivileged access generates a NOCP UsageFault. */
fpuAccessReserved = (0xA << 20), /**< Reserved. */
fpuAccessFull = (0xF << 20) /**< Full access. */
} SYSTEM_FpuAccess_TypeDef;
#endif
/*******************************************************************************
***************************** PROTOTYPES **********************************
******************************************************************************/
void SYSTEM_ChipRevisionGet(SYSTEM_ChipRevision_TypeDef *rev);
SYSTEM_PartFamily_TypeDef SYSTEM_GetFamily(void);
#if defined(_DEVINFO_DEVINFOREV_DEVINFOREV_MASK) || defined(_DEVINFO_INFO_DEVINFOREV_MASK)
/***************************************************************************//**
* @brief
* Get DEVINFO revision.
*
* @return
* Revision of the DEVINFO contents.
******************************************************************************/
__STATIC_INLINE uint8_t SYSTEM_GetDevinfoRev(void)
{
#if defined(_DEVINFO_DEVINFOREV_DEVINFOREV_MASK)
return (uint8_t)((DEVINFO->DEVINFOREV & _DEVINFO_DEVINFOREV_DEVINFOREV_MASK)
>> _DEVINFO_DEVINFOREV_DEVINFOREV_SHIFT);
#elif defined(_DEVINFO_INFO_DEVINFOREV_MASK)
return (uint8_t)((DEVINFO->INFO & _DEVINFO_INFO_DEVINFOREV_MASK)
>> _DEVINFO_INFO_DEVINFOREV_SHIFT);
#endif
}
#endif
#if defined(__FPU_PRESENT) && (__FPU_PRESENT == 1)
/***************************************************************************//**
* @brief
* Set floating point co-processor (FPU) access mode.
*
* @param[in] accessMode
* Floating point co-processor access mode. See @ref SYSTEM_FpuAccess_TypeDef
* for details.
******************************************************************************/
__STATIC_INLINE void SYSTEM_FpuAccessModeSet(SYSTEM_FpuAccess_TypeDef accessMode)
{
SCB->CPACR = (SCB->CPACR & ~(0xFUL << 20)) | (uint32_t)accessMode;
}
#endif
/** @} (end addtogroup system) */
#ifdef __cplusplus
}
#endif
#endif /* EM_SYSTEM_H */

View File

@@ -0,0 +1,91 @@
/***************************************************************************//**
* @file
* @brief System API (Generic)
*******************************************************************************
* # License
* <b>Copyright 2023 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* 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.
*
******************************************************************************/
#ifndef EM_SYSTEM_GENERIC_H
#define EM_SYSTEM_GENERIC_H
#include <stdint.h>
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
/***************************************************************************//**
* @addtogroup system
* @{
******************************************************************************/
/*******************************************************************************
******************************** ENUMS ************************************
******************************************************************************/
/** Family security capability. */
typedef enum {
securityCapabilityUnknown, /**< Unknown security capability. */
securityCapabilityNA, /**< Security capability not applicable. */
securityCapabilityBasic, /**< Basic security capability. */
securityCapabilityRoT, /**< Root of Trust security capability. */
securityCapabilitySE, /**< Secure Element security capability. */
securityCapabilityVault /**< Secure Vault security capability. */
} SYSTEM_SecurityCapability_TypeDef;
/*******************************************************************************
******************************* STRUCTS ***********************************
******************************************************************************/
/** DEVINFO calibration address/value pair. */
typedef struct {
uint32_t address; /**< Peripheral calibration register address. */
uint32_t calValue; /**< Calibration value for register at address. */
}
SYSTEM_CalAddrVal_TypeDef;
/*******************************************************************************
***************************** PROTOTYPES **********************************
******************************************************************************/
bool SYSTEM_GetCalibrationValue(volatile uint32_t *regAddress);
SYSTEM_SecurityCapability_TypeDef SYSTEM_GetSecurityCapability(void);
uint64_t SYSTEM_GetUnique(void);
uint8_t SYSTEM_GetProdRev(void);
uint32_t SYSTEM_GetSRAMBaseAddress(void);
uint16_t SYSTEM_GetSRAMSize(void);
uint16_t SYSTEM_GetFlashSize(void);
uint32_t SYSTEM_GetFlashPageSize(void);
uint16_t SYSTEM_GetPartNumber(void);
uint8_t SYSTEM_GetCalibrationTemperature(void);
/** @} (end addtogroup system) */
#ifdef __cplusplus
}
#endif
#endif /* EM_SYSTEM_GENERIC_H */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,773 @@
/***************************************************************************//**
* @file
* @brief Digital to Analog Converter (VDAC) peripheral API
*******************************************************************************
* # License
* <b>Copyright 2018 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* 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.
*
******************************************************************************/
#ifndef EM_VDAC_H
#define EM_VDAC_H
#include "em_device.h"
#if defined(VDAC_COUNT) && (VDAC_COUNT > 0)
#include "sl_assert.h"
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
/***************************************************************************//**
* @addtogroup vdac VDAC - Voltage DAC
* @brief Digital to Analog Voltage Converter (VDAC) Peripheral API
*
* @details
* This module contains functions to control the VDAC peripheral of Silicon
* Labs' 32-bit MCUs and SoCs. VDAC converts digital values to analog
* signals at up to 500 ksps with 12-bit accuracy. VDAC is designed for
* low energy consumption, but can also provide very good performance.
*
* The following steps are necessary for basic operation:
*
* Clock enable:
* @code
CMU_ClockEnable(cmuClock_VDAC0, true);@endcode
*
* Initialize the VDAC with default settings and modify selected fields:
* @code
VDAC_Init_TypeDef vdacInit = VDAC_INIT_DEFAULT;
VDAC_InitChannel_TypeDef vdacChInit = VDAC_INITCHANNEL_DEFAULT;
// Set prescaler to get 1 MHz VDAC clock frequency.
vdacInit.prescaler = VDAC_PrescaleCalc(1000000, true, 0); // function call for series 0/1
VDAC_Init(VDAC0, &vdacInit);
vdacChInit.enable = true;
VDAC_InitChannel(VDAC0, &vdacChInit, 0);@endcode
*
* Perform a conversion:
* @code
VDAC_ChannelOutputSet(VDAC0, 0, 250);@endcode
*
* @note The output stage of a VDAC channel consists of an on-chip operational
* amplifier (OPAMP) in the OPAMP module. This OPAMP is highly configurable;
* and to exploit the VDAC functionality fully, configure the OPAMP using
* the OPAMP API. Using the OPAMP API also loads OPAMP calibration values.
* The default (reset) settings of OPAMP is sufficient for many applications.
* @{
******************************************************************************/
/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
/** Validation of VDAC register block pointer reference for assert statements.*/
#if VDAC_COUNT == 1
#define VDAC_REF_VALID(ref) ((ref) == VDAC0)
#elif VDAC_COUNT == 2
#define VDAC_REF_VALID(ref) (((ref) == VDAC0) || ((ref) == VDAC1))
#else
#error "Undefined number of VDACs."
#endif
/** @endcond */
/*******************************************************************************
******************************** ENUMS ************************************
******************************************************************************/
#if !defined(_SILICON_LABS_32B_SERIES_2)
/** Channel refresh period. */
typedef enum {
vdacRefresh8 = _VDAC_CTRL_REFRESHPERIOD_8CYCLES, /**< Refresh every 8 clock cycles. */
vdacRefresh16 = _VDAC_CTRL_REFRESHPERIOD_16CYCLES, /**< Refresh every 16 clock cycles. */
vdacRefresh32 = _VDAC_CTRL_REFRESHPERIOD_32CYCLES, /**< Refresh every 32 clock cycles. */
vdacRefresh64 = _VDAC_CTRL_REFRESHPERIOD_64CYCLES, /**< Refresh every 64 clock cycles. */
} VDAC_Refresh_TypeDef;
/** Reference voltage for VDAC. */
typedef enum {
vdacRef1V25Ln = _VDAC_CTRL_REFSEL_1V25LN, /**< Internal low noise 1.25 V band gap reference. */
vdacRef2V5Ln = _VDAC_CTRL_REFSEL_2V5LN, /**< Internal low noise 2.5 V band gap reference. */
vdacRef1V25 = _VDAC_CTRL_REFSEL_1V25, /**< Internal 1.25 V band gap reference. */
vdacRef2V5 = _VDAC_CTRL_REFSEL_2V5, /**< Internal 2.5 V band gap reference. */
vdacRefAvdd = _VDAC_CTRL_REFSEL_VDD, /**< AVDD reference. */
vdacRefExtPin = _VDAC_CTRL_REFSEL_EXT, /**< External pin reference. */
} VDAC_Ref_TypeDef;
/** Peripheral Reflex System signal used to trigger VDAC channel conversion. */
typedef enum {
vdacPrsSelCh0 = _VDAC_CH0CTRL_PRSSEL_PRSCH0, /**< PRS ch 0 triggers conversion. */
vdacPrsSelCh1 = _VDAC_CH0CTRL_PRSSEL_PRSCH1, /**< PRS ch 1 triggers conversion. */
vdacPrsSelCh2 = _VDAC_CH0CTRL_PRSSEL_PRSCH2, /**< PRS ch 2 triggers conversion. */
vdacPrsSelCh3 = _VDAC_CH0CTRL_PRSSEL_PRSCH3, /**< PRS ch 3 triggers conversion. */
vdacPrsSelCh4 = _VDAC_CH0CTRL_PRSSEL_PRSCH4, /**< PRS ch 4 triggers conversion. */
vdacPrsSelCh5 = _VDAC_CH0CTRL_PRSSEL_PRSCH5, /**< PRS ch 5 triggers conversion. */
vdacPrsSelCh6 = _VDAC_CH0CTRL_PRSSEL_PRSCH6, /**< PRS ch 6 triggers conversion. */
vdacPrsSelCh7 = _VDAC_CH0CTRL_PRSSEL_PRSCH7, /**< PRS ch 7 triggers conversion. */
#if defined(_VDAC_CH0CTRL_PRSSEL_PRSCH8)
vdacPrsSelCh8 = _VDAC_CH0CTRL_PRSSEL_PRSCH8, /**< PRS ch 8 triggers conversion. */
#endif
#if defined(_VDAC_CH0CTRL_PRSSEL_PRSCH9)
vdacPrsSelCh9 = _VDAC_CH0CTRL_PRSSEL_PRSCH9, /**< PRS ch 9 triggers conversion. */
#endif
#if defined(_VDAC_CH0CTRL_PRSSEL_PRSCH10)
vdacPrsSelCh10 = _VDAC_CH0CTRL_PRSSEL_PRSCH10, /**< PRS ch 10 triggers conversion. */
#endif
#if defined(_VDAC_CH0CTRL_PRSSEL_PRSCH11)
vdacPrsSelCh11 = _VDAC_CH0CTRL_PRSSEL_PRSCH11, /**< PRS ch 11 triggers conversion. */
#endif
} VDAC_PrsSel_TypeDef;
/** Channel conversion trigger mode. */
typedef enum {
vdacTrigModeSw = _VDAC_CH0CTRL_TRIGMODE_SW, /**< Channel is triggered by CHnDATA or COMBDATA write. */
vdacTrigModePrs = _VDAC_CH0CTRL_TRIGMODE_PRS, /**< Channel is triggered by PRS input. */
vdacTrigModeRefresh = _VDAC_CH0CTRL_TRIGMODE_REFRESH, /**< Channel is triggered by Refresh timer. */
vdacTrigModeSwPrs = _VDAC_CH0CTRL_TRIGMODE_SWPRS, /**< Channel is triggered by CHnDATA/COMBDATA write or PRS input. */
vdacTrigModeSwRefresh = _VDAC_CH0CTRL_TRIGMODE_SWREFRESH, /**< Channel is triggered by CHnDATA/COMBDATA write or Refresh timer. */
vdacTrigModeLesense = _VDAC_CH0CTRL_TRIGMODE_LESENSE, /**< Channel is triggered by LESENSE. */
} VDAC_TrigMode_TypeDef;
/*******************************************************************************
******************************* STRUCTS ***********************************
******************************************************************************/
/** VDAC initialization structure, common for both channels. */
typedef struct {
/** Selects between main and alternate output path calibration values. */
bool mainCalibration;
/** Selects clock from asynchronous or synchronous (with respect to
peripheral clock) source. */
bool asyncClockMode;
/** Warm-up mode, keep VDAC on (in idle) - or shutdown between conversions.*/
bool warmupKeepOn;
/** Channel refresh period. */
VDAC_Refresh_TypeDef refresh;
/** Prescaler for VDAC clock. Clock is source clock divided by prescaler+1. */
uint32_t prescaler;
/** Reference voltage to use. */
VDAC_Ref_TypeDef reference;
/** Enable/disable reset of prescaler on CH 0 start. */
bool ch0ResetPre;
/** Enable/disable output enable control by CH1 PRS signal. */
bool outEnablePRS;
/** Enable/disable sine mode. */
bool sineEnable;
/** Select if single ended or differential output mode. */
bool diff;
} VDAC_Init_TypeDef;
/** Default configuration for VDAC initialization structure. */
#define VDAC_INIT_DEFAULT \
{ \
true, /* Use main output path calibration values. */ \
false, /* Use synchronous clock mode. */ \
false, /* Turn off between sample off conversions.*/ \
vdacRefresh8, /* Refresh every 8th cycle. */ \
0, /* No prescaling. */ \
vdacRef1V25Ln, /* 1.25 V internal low noise reference. */ \
false, /* Do not reset prescaler on CH 0 start. */ \
false, /* VDAC output enable always on. */ \
false, /* Disable sine mode. */ \
false /* Single ended mode. */ \
}
/** VDAC channel initialization structure. */
typedef struct {
/** Enable channel. */
bool enable;
/**
* Peripheral reflex system trigger selection. Only applicable if @p trigMode
* is set to @p vdacTrigModePrs or @p vdacTrigModeSwPrs. */
VDAC_PrsSel_TypeDef prsSel;
/** Treat the PRS signal asynchronously. */
bool prsAsync;
/** Channel conversion trigger mode. */
VDAC_TrigMode_TypeDef trigMode;
/** Set channel conversion mode to sample/shut-off mode. Default is
* continuous.*/
bool sampleOffMode;
} VDAC_InitChannel_TypeDef;
/** Default configuration for VDAC channel initialization structure. */
#define VDAC_INITCHANNEL_DEFAULT \
{ \
false, /* Leave channel disabled when initialization is done. */ \
vdacPrsSelCh0, /* PRS CH 0 triggers conversion. */ \
false, /* Treat PRS channel as a synchronous signal. */ \
vdacTrigModeSw, /* Conversion trigged by CH0DATA or COMBDATA write. */ \
false, /* Channel conversion set to continuous. */ \
}
#else // defined(_SILICON_LABS_32B_SERIES_2)
/** Channel refresh period. */
typedef enum {
vdacRefresh2 = _VDAC_CFG_REFRESHPERIOD_CYCLES2, /**< Refresh every 2 clock cycles. */
vdacRefresh4 = _VDAC_CFG_REFRESHPERIOD_CYCLES4, /**< Refresh every 4 clock cycles. */
vdacRefresh8 = _VDAC_CFG_REFRESHPERIOD_CYCLES8, /**< Refresh every 8 clock cycles. */
vdacRefresh16 = _VDAC_CFG_REFRESHPERIOD_CYCLES16, /**< Refresh every 16 clock cycles. */
vdacRefresh32 = _VDAC_CFG_REFRESHPERIOD_CYCLES32, /**< Refresh every 32 clock cycles. */
vdacRefresh64 = _VDAC_CFG_REFRESHPERIOD_CYCLES64, /**< Refresh every 64 clock cycles. */
vdacRefresh128 = _VDAC_CFG_REFRESHPERIOD_CYCLES128, /**< Refresh every 128 clock cycles. */
vdacRefresh256 = _VDAC_CFG_REFRESHPERIOD_CYCLES256, /**< Refresh every 256 clock cycles. */
} VDAC_Refresh_TypeDef;
/** Timer overflow period. */
typedef enum {
vdacCycles2 = _VDAC_CFG_TIMEROVRFLOWPERIOD_CYCLES2, /**< Overflows every 2 clock cycles. */
vdacCycles4 = _VDAC_CFG_TIMEROVRFLOWPERIOD_CYCLES4, /**< Overflows every 4 clock cycles. */
vdacCycles8 = _VDAC_CFG_TIMEROVRFLOWPERIOD_CYCLES8, /**< Overflows every 8 clock cycles. */
vdacCycles16 = _VDAC_CFG_TIMEROVRFLOWPERIOD_CYCLES16, /**< Overflows every 16 clock cycles. */
vdacCycles32 = _VDAC_CFG_TIMEROVRFLOWPERIOD_CYCLES32, /**< Overflows every 32 clock cycles. */
vdacCycles64 = _VDAC_CFG_TIMEROVRFLOWPERIOD_CYCLES64 /**< Overflows every 64 clock cycles. */
} VDAC_TimerOverflow_TypeDef;
/** Reference voltage for VDAC. */
typedef enum {
vdacRef1V25 = _VDAC_CFG_REFRSEL_V125, /**< Internal 1.25 V band gap reference. */
vdacRef2V5 = _VDAC_CFG_REFRSEL_V25, /**< Internal 2.5 V band gap reference. */
vdacRefAvdd = _VDAC_CFG_REFRSEL_VDD, /**< AVDD reference. */
vdacRefExtPin = _VDAC_CFG_REFRSEL_EXT, /**< External pin reference. */
} VDAC_Ref_TypeDef;
/** Refresh source for VDAC. */
typedef enum {
vdacRefreshSrcNone = _VDAC_CH0CFG_REFRESHSOURCE_NONE, /**< No refresh source. */
vdacRefreshSrcRefreshTimer = _VDAC_CH0CFG_REFRESHSOURCE_REFRESHTIMER,/**< Refresh triggered by refresh timer overflow. */
vdacRefreshSrcSyncPrs = _VDAC_CH0CFG_REFRESHSOURCE_SYNCPRS, /**< Refresh triggered by sync PRS. */
vdacRefreshSrcAsyncPrs = _VDAC_CH0CFG_REFRESHSOURCE_ASYNCPRS, /**< Refresh triggered by async PRS. */
} VDAC_RefreshSource_TypeDef;
/** Channel conversion trigger mode. */
typedef enum {
vdacTrigModeNone = _VDAC_CH0CFG_TRIGMODE_NONE, /**< No conversion trigger source selected. */
vdacTrigModeSw = _VDAC_CH0CFG_TRIGMODE_SW, /**< Channel is triggered by CHnDATA or COMBDATA write. */
vdacTrigModeSyncPrs = _VDAC_CH0CFG_TRIGMODE_SYNCPRS, /**< Channel is triggered by Sync PRS input. */
#if defined(LESENSE_PRESENT) && defined(_VDAC_CH0CFG_TRIGMODE_LESENSE)
vdacTrigModeLesense = _VDAC_CH0CFG_TRIGMODE_LESENSE, /**< Channel is triggered by LESENSE. */
#endif
vdacTrigModeInternalTimer = _VDAC_CH0CFG_TRIGMODE_INTERNALTIMER, /**< Channel is triggered by Internal Timer. */
vdacTrigModeAsyncPrs = _VDAC_CH0CFG_TRIGMODE_ASYNCPRS /**< Channel is triggered by Async PRS input. */
} VDAC_TrigMode_TypeDef;
/** Channel power mode. */
typedef enum {
vdacPowerModeHighPower = _VDAC_CH0CFG_POWERMODE_HIGHPOWER, /**< High power buffer mode. */
vdacPowerModeLowPower = _VDAC_CH0CFG_POWERMODE_LOWPOWER /**< Low power buffer mode. */
} VDAC_PowerMode_TypeDef;
/** VDAC channel Abus port selection. */
typedef enum {
/** No GPIO selected. */
vdacChPortNone = _VDAC_OUTCTRL_ABUSPORTSELCH0_NONE,
/** Port A selected. */
vdacChPortA = _VDAC_OUTCTRL_ABUSPORTSELCH0_PORTA,
/** Port B selected. */
vdacChPortB = _VDAC_OUTCTRL_ABUSPORTSELCH0_PORTB,
/** Port C selected. */
vdacChPortC = _VDAC_OUTCTRL_ABUSPORTSELCH0_PORTC,
/** Port D selected. */
vdacChPortD = _VDAC_OUTCTRL_ABUSPORTSELCH0_PORTD,
} VDAC_ChPortSel_t;
/*******************************************************************************
******************************* STRUCTS ***********************************
******************************************************************************/
/** VDAC initialization structure, common for both channels. */
typedef struct {
/** Number of prescaled CLK_DAC + 1 for the vdac to warmup. */
uint32_t warmupTime;
/** Halt during debug. */
bool dbgHalt;
/** Always allow clk_dac. */
bool onDemandClk;
/** DMA Wakeup. */
bool dmaWakeUp;
/** Bias keep warm enable. */
bool biasKeepWarm;
/** Channel refresh period. */
VDAC_Refresh_TypeDef refresh;
/** Internal timer overflow period. */
VDAC_TimerOverflow_TypeDef timerOverflow;
/** Prescaler for VDAC clock. Clock is source clock divided by prescaler+1. */
uint32_t prescaler;
/** Reference voltage to use. */
VDAC_Ref_TypeDef reference;
/** Enable/disable reset of prescaler on CH 0 start. */
bool ch0ResetPre;
/** Sine reset mode. */
bool sineReset;
/** Enable/disable sine mode. */
bool sineEnable;
/** Select if single ended or differential output mode. */
bool diff;
#if defined(VDAC_CFG_SINEMODEPRS)
/** PRS controlled sinemode enable. */
bool sineModePrsEnable;
#endif
#if defined(VDAC_CFG_OUTENPRS)
/** PRS controlled channel output enable. */
bool prsOutEnable;
#endif
} VDAC_Init_TypeDef;
#if defined(VDAC_CFG_SINEMODEPRS)
/** Default configuration for VDAC initialization structure. */
#define VDAC_INIT_DEFAULT \
{ \
_VDAC_CFG_WARMUPTIME_DEFAULT, /* Number of prescaled DAC_CLK for Vdac to warmup. */ \
false, /* Continue while debugging. */ \
false, /* On demand clock. */ \
false, /* DMA wake up. */ \
false, /* Bias keep warm. */ \
vdacRefresh2, /* Refresh every 2th cycle. */ \
vdacCycles2, /* Internal overflow every 2th cycle. */ \
0, /* No prescaling. */ \
vdacRef1V25, /* 1.25 V internal low noise reference. */ \
false, /* Do not reset prescaler on CH 0 start. */ \
false, /* Sine wave is stopped at the sample its currently outputting. */ \
false, /* Disable sine mode. */ \
false, /* Differential mode. */ \
false, /* PRS controlled sinemode. */ \
false, /* PRS controlled output enable. */ \
}
#else
/** Default configuration for VDAC initialization structure. */
#define VDAC_INIT_DEFAULT \
{ \
_VDAC_CFG_WARMUPTIME_DEFAULT, /* Number of prescaled DAC_CLK for Vdac to warmup. */ \
false, /* Continue while debugging. */ \
false, /* On demand clock. */ \
false, /* DMA wake up. */ \
false, /* Bias keep warm. */ \
vdacRefresh2, /* Refresh every 2th cycle. */ \
vdacCycles2, /* Internal overflow every 2th cycle. */ \
0, /* No prescaling. */ \
vdacRef1V25, /* 1.25 V internal low noise reference. */ \
false, /* Do not reset prescaler on CH 0 start. */ \
false, /* Sine wave is stopped at the sample its currently outputting. */ \
false, /* Disable sine mode. */ \
false, /* Differential mode. */ \
}
#endif
#if defined(VDAC_CFG_SINEMODEPRS)
/** Sine mode configuration for VDAC initialization structure. */
#define VDAC_INIT_SINE_GENERATION_MODE \
{ \
_VDAC_CFG_WARMUPTIME_DEFAULT, /* Number of prescaled DAC_CLK for Vdac to warmup. */ \
false, /* Continue while debugging. */ \
true, /* On demand clock. */ \
false, /* DMA wake up. */ \
false, /* Bias keep warm. */ \
vdacRefresh8, /* Refresh every 8th cycle. */ \
vdacCycles2, /* Internal overflow every 8th cycle. */ \
0, /* No prescaling. */ \
vdacRef1V25, /* 1.25 V internal low noise reference. */ \
false, /* Do not reset prescaler on CH 0 start. */ \
false, /* Sine wave is stopped at the sample its currently outputting. */ \
true, /* Enable sine mode. */ \
false, /* Differential mode. */ \
false, /* PRS controlled sinemode. */ \
false, /* PRS controlled output enable. */ \
}
#else
/** Sine mode configuration for VDAC initialization structure. */
#define VDAC_INIT_SINE_GENERATION_MODE \
{ \
_VDAC_CFG_WARMUPTIME_DEFAULT, /* Number of prescaled DAC_CLK for Vdac to warmup. */ \
false, /* Continue while debugging. */ \
true, /* On demand clock. */ \
false, /* DMA wake up. */ \
false, /* Bias keep warm. */ \
vdacRefresh8, /* Refresh every 8th cycle. */ \
vdacCycles2, /* Internal overflow every 8th cycle. */ \
0, /* No prescaling. */ \
vdacRef1V25, /* 1.25 V internal low noise reference. */ \
false, /* Do not reset prescaler on CH 0 start. */ \
false, /* Sine wave is stopped at the sample its currently outputting. */ \
true, /* Enable sine mode. */ \
false, /* Differential mode. */ \
}
#endif
/** VDAC channel initialization structure. */
typedef struct {
/** Enable channel. */
bool enable;
/** Warm-up mode, keep VDAC on (in idle) - or shutdown between conversions.*/
bool warmupKeepOn;
/** Select high capacitance load mode in conjunction with high power. */
bool highCapLoadEnable;
/** Channel x FIFO Low threshold data valid level. */
uint32_t fifoLowDataThreshold;
/** Channel refresh source. */
VDAC_RefreshSource_TypeDef chRefreshSource;
/** Channel conversion trigger mode. */
VDAC_TrigMode_TypeDef trigMode;
/** Channel power mode. */
VDAC_PowerMode_TypeDef powerMode;
/** Set channel conversion mode to sample/shut-off mode. Default is
* continuous.*/
bool sampleOffMode;
/** Vdac channel output pin. */
uint32_t pin;
/** Vdac channel output port. */
VDAC_ChPortSel_t port;
/** Short High power and low power output. */
bool shortOutput;
/** Alternative output enable. */
bool auxOutEnable;
/** Main output enable. */
bool mainOutEnable;
/** Channel output hold time. */
uint32_t holdOutTime;
} VDAC_InitChannel_TypeDef;
/** Default configuration for VDAC channel initialization structure. */
#define VDAC_INITCHANNEL_DEFAULT \
{ \
false, /* Leave channel disabled when initialization is done. */ \
false, /* Turn off between sample off conversions.*/ \
true, /* Enable High cap mode. */ \
0, /* FIFO data low watermark at 0. */ \
vdacRefreshSrcNone, /* Channel refresh source. */ \
vdacTrigModeSw, /* Conversion trigged by CH0DATA or COMBDATA write. */ \
vdacPowerModeHighPower, /* High power mode enabled. */ \
false, /* Continuous conversion mode. */ \
0, /* ABUS pin selected. */ \
vdacChPortNone, /* No Analog bus port selected. */ \
false, /* Output not shorted */ \
false, /* Alternative output disabled. */ \
true, /* Main output enabled. */ \
0, /* Hold out time. Previously called settle time */ \
}
#endif
/*******************************************************************************
***************************** PROTOTYPES **********************************
******************************************************************************/
void VDAC_ChannelOutputSet(VDAC_TypeDef *vdac,
unsigned int channel,
uint32_t value);
void VDAC_Enable(VDAC_TypeDef *vdac, unsigned int ch, bool enable);
void VDAC_Init(VDAC_TypeDef *vdac, const VDAC_Init_TypeDef *init);
void VDAC_InitChannel(VDAC_TypeDef *vdac,
const VDAC_InitChannel_TypeDef *init,
unsigned int ch);
#if defined(_SILICON_LABS_32B_SERIES_2)
/***************************************************************************//**
* @brief
* Start/stop Sinemode.
*
* @details
* This function sends the sine mode start/stop signal to the DAC.
*
* @param[in] vdac
* Pointer to VDAC peripheral register block.
*
* @param[in] start
* True to start the Sine mode, false to stop it.
******************************************************************************/
__STATIC_INLINE void VDAC_SineModeStart(VDAC_TypeDef *vdac, bool start)
{
EFM_ASSERT(VDAC_REF_VALID(vdac));
while (0UL != (vdac->STATUS & VDAC_STATUS_SYNCBUSY)) {
}
if (start) {
vdac->CMD = VDAC_CMD_SINEMODESTART;
while (0UL == (vdac->STATUS & VDAC_STATUS_SINEACTIVE)) {
}
} else {
vdac->CMD = VDAC_CMD_SINEMODESTOP;
while (0UL != (vdac->STATUS & VDAC_STATUS_SINEACTIVE)) {
}
}
}
#endif
/***************************************************************************//**
* @brief
* Set the output signal of VDAC channel 0 to a given value.
*
* @details
* This function sets the output signal of VDAC channel 0 by writing @p value
* to the CH0DATA register.
*
* @param[in] vdac
* Pointer to VDAC peripheral register block.
*
* @param[in] value
* Value to write to channel 0 output register CH0DATA.
******************************************************************************/
__STATIC_INLINE void VDAC_Channel0OutputSet(VDAC_TypeDef *vdac,
uint32_t value)
{
#if defined(_SILICON_LABS_32B_SERIES_0) || defined(_SILICON_LABS_32B_SERIES_1)
EFM_ASSERT(value <= _VDAC_CH0DATA_MASK);
vdac->CH0DATA = value;
#elif defined(_SILICON_LABS_32B_SERIES_2)
EFM_ASSERT(value <= _VDAC_CH0F_MASK);
vdac->CH0F = value;
#endif
}
/***************************************************************************//**
* @brief
* Set the output signal of VDAC channel 1 to a given value.
*
* @details
* This function sets the output signal of VDAC channel 1 by writing @p value
* to the CH1DATA register.
*
* @param[in] vdac
* Pointer to VDAC peripheral register block.
*
* @param[in] value
* Value to write to channel 1 output register CH1DATA.
******************************************************************************/
__STATIC_INLINE void VDAC_Channel1OutputSet(VDAC_TypeDef *vdac,
uint32_t value)
{
#if defined(_SILICON_LABS_32B_SERIES_0) || defined(_SILICON_LABS_32B_SERIES_1)
EFM_ASSERT(value <= _VDAC_CH1DATA_MASK);
vdac->CH1DATA = value;
#elif defined(_SILICON_LABS_32B_SERIES_2)
EFM_ASSERT(value <= _VDAC_CH1F_MASK);
vdac->CH1F = value;
#endif
}
/***************************************************************************//**
* @brief
* Clear one or more pending VDAC interrupts.
*
* @param[in] vdac
* Pointer to VDAC peripheral register block.
*
* @param[in] flags
* Pending VDAC interrupt source to clear. Use a bitwise logic OR combination
* of valid interrupt flags for the VDAC module (VDAC_IF_nnn).
******************************************************************************/
__STATIC_INLINE void VDAC_IntClear(VDAC_TypeDef *vdac, uint32_t flags)
{
#if defined(VDAC_HAS_SET_CLEAR)
vdac->IF_CLR = flags;
#else
vdac->IFC = flags;
#endif
}
/***************************************************************************//**
* @brief
* Disable one or more VDAC interrupts.
*
* @param[in] vdac
* Pointer to VDAC peripheral register block.
*
* @param[in] flags
* VDAC interrupt sources to disable. Use a bitwise logic OR combination of
* valid interrupt flags for the VDAC module (VDAC_IF_nnn).
******************************************************************************/
__STATIC_INLINE void VDAC_IntDisable(VDAC_TypeDef *vdac, uint32_t flags)
{
#if defined(VDAC_HAS_SET_CLEAR)
vdac->IEN_CLR = flags;
#else
vdac->IEN &= ~flags;
#endif
}
/***************************************************************************//**
* @brief
* Enable one or more VDAC interrupts.
*
* @note
* Depending on the use, a pending interrupt may already be set prior to
* enabling the interrupt. To ignore a pending interrupt, consider using
* VDAC_IntClear() prior to enabling the interrupt.
*
* @param[in] vdac
* Pointer to VDAC peripheral register block.
*
* @param[in] flags
* VDAC interrupt sources to enable. Use a bitwise logic OR combination
* of valid interrupt flags for the VDAC module (VDAC_IF_nnn).
******************************************************************************/
__STATIC_INLINE void VDAC_IntEnable(VDAC_TypeDef *vdac, uint32_t flags)
{
#if defined(VDAC_HAS_SET_CLEAR)
vdac->IEN_SET = flags;
#else
vdac->IEN |= flags;
#endif
}
/***************************************************************************//**
* @brief
* Get pending VDAC interrupt flags.
*
* @note
* The event bits are not cleared by the use of this function.
*
* @param[in] vdac
* Pointer to VDAC peripheral register block.
*
* @return
* VDAC interrupt sources pending. Use a bitwise logic OR combination
* of valid interrupt flags for the VDAC module (VDAC_IF_nnn).
******************************************************************************/
__STATIC_INLINE uint32_t VDAC_IntGet(VDAC_TypeDef *vdac)
{
return vdac->IF;
}
/***************************************************************************//**
* @brief
* Get enabled and pending VDAC interrupt flags.
* Useful for handling more interrupt sources in the same interrupt handler.
*
* @param[in] vdac
* Pointer to VDAC peripheral register block.
*
* @note
* Interrupt flags are not cleared by the use of this function.
*
* @return
* Pending and enabled VDAC interrupt sources.
* The return value is the bitwise AND combination of
* - the OR combination of enabled interrupt sources in VDACx_IEN_nnn
* register (VDACx_IEN_nnn) and
* - the OR combination of valid interrupt flags of the VDAC module
* (VDACx_IF_nnn).
******************************************************************************/
__STATIC_INLINE uint32_t VDAC_IntGetEnabled(VDAC_TypeDef *vdac)
{
uint32_t ien = vdac->IEN;
/* Bitwise AND of pending and enabled interrupts */
return vdac->IF & ien;
}
/***************************************************************************//**
* @brief
* Set one or more pending VDAC interrupts from SW.
*
* @param[in] vdac
* Pointer to VDAC peripheral register block.
*
* @param[in] flags
* VDAC interrupt sources to set to pending. Use a bitwise logic OR
* combination of valid interrupt flags for the VDAC module (VDAC_IF_nnn).
******************************************************************************/
__STATIC_INLINE void VDAC_IntSet(VDAC_TypeDef *vdac, uint32_t flags)
{
#if defined(VDAC_HAS_SET_CLEAR)
vdac->IF_SET = flags;
#else
vdac->IFS = flags;
#endif
}
#if defined(_SILICON_LABS_32B_SERIES_2)
/***************************************************************************//**
* @brief
* Get the VDAC Status register.
*
* @param[in] vdac
* Pointer to VDAC peripheral register block.
*
* @return
* Current STATUS register value.
******************************************************************************/
__STATIC_INLINE uint32_t VDAC_GetStatus(VDAC_TypeDef *vdac)
{
return vdac->STATUS;
}
#endif
#if defined(_SILICON_LABS_32B_SERIES_0) || defined(_SILICON_LABS_32B_SERIES_1)
uint32_t VDAC_PrescaleCalc(uint32_t vdacFreq, bool syncMode, uint32_t hfperFreq);
#else
uint32_t VDAC_PrescaleCalc(VDAC_TypeDef *vdac, uint32_t vdacFreq);
#endif
void VDAC_Reset(VDAC_TypeDef *vdac);
/** @} (end addtogroup vdac) */
#ifdef __cplusplus
}
#endif
#endif /* defined(VDAC_COUNT) && (VDAC_COUNT > 0) */
#endif /* EM_VDAC_H */

View File

@@ -0,0 +1,68 @@
/***************************************************************************//**
* @file
* @brief CMSIS and EMLIB versions
*******************************************************************************
* # License
* <b>Copyright 2018 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* 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.
*
******************************************************************************/
#ifndef EM_VERSION_H
#define EM_VERSION_H
#include "em_device.h"
#ifdef __cplusplus
extern "C" {
#endif
/***************************************************************************//**
* @addtogroup version VERSION - Version Defines
* @brief Version API
* @details
* Macros specifying the EMLIB and CMSIS version.
* @{
******************************************************************************/
/* *INDENT-OFF* */
/** Version number of targeted CMSIS package. */
#define _CMSIS_VERSION 5.8.0
/* *INDENT-ON* */
/** Major version of CMSIS. */
#define _CMSIS_VERSION_MAJOR 5
/** Minor version of CMSIS. */
#define _CMSIS_VERSION_MINOR 8
/** Patch revision of CMSIS. */
#define _CMSIS_VERSION_PATCH 0
/** @} (end addtogroup version) */
#ifdef __cplusplus
}
#endif
#endif /* EM_VERSION_H */

View File

@@ -0,0 +1,455 @@
/***************************************************************************//**
* @file
* @brief Watchdog (WDOG) peripheral API
*******************************************************************************
* # License
* <b>Copyright 2018 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* 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.
*
******************************************************************************/
#ifndef EM_WDOG_H
#define EM_WDOG_H
#include "em_device.h"
#if defined(WDOG_COUNT) && (WDOG_COUNT > 0)
#include <stdbool.h>
#include "sl_common.h"
#ifdef __cplusplus
extern "C" {
#endif
/***************************************************************************//**
* @addtogroup wdog
* @{
******************************************************************************/
/*******************************************************************************
******************************* DEFINES ***********************************
******************************************************************************/
/** Default WDOG instance for deprecated functions. */
#if !defined(DEFAULT_WDOG)
#if defined(WDOG0)
#define DEFAULT_WDOG WDOG0
#elif defined(WDOG)
#define DEFAULT_WDOG WDOG
#endif
#endif
/*******************************************************************************
******************************** ENUMS ************************************
******************************************************************************/
/** Watchdog clock selection. */
#if defined(_WDOG_CTRL_CLKSEL_MASK)
typedef enum {
wdogClkSelULFRCO = _WDOG_CTRL_CLKSEL_ULFRCO, /**< Ultra low frequency (1 kHz) clock */
wdogClkSelLFRCO = _WDOG_CTRL_CLKSEL_LFRCO, /**< Low frequency RC oscillator */
wdogClkSelLFXO = _WDOG_CTRL_CLKSEL_LFXO /**< Low frequency crystal oscillator */
} WDOG_ClkSel_TypeDef;
#endif
/** Watchdog period selection. */
typedef enum {
wdogPeriod_9 = 0x0, /**< 9 clock periods */
wdogPeriod_17 = 0x1, /**< 17 clock periods */
wdogPeriod_33 = 0x2, /**< 33 clock periods */
wdogPeriod_65 = 0x3, /**< 65 clock periods */
wdogPeriod_129 = 0x4, /**< 129 clock periods */
wdogPeriod_257 = 0x5, /**< 257 clock periods */
wdogPeriod_513 = 0x6, /**< 513 clock periods */
wdogPeriod_1k = 0x7, /**< 1025 clock periods */
wdogPeriod_2k = 0x8, /**< 2049 clock periods */
wdogPeriod_4k = 0x9, /**< 4097 clock periods */
wdogPeriod_8k = 0xA, /**< 8193 clock periods */
wdogPeriod_16k = 0xB, /**< 16385 clock periods */
wdogPeriod_32k = 0xC, /**< 32769 clock periods */
wdogPeriod_64k = 0xD, /**< 65537 clock periods */
wdogPeriod_128k = 0xE, /**< 131073 clock periods */
wdogPeriod_256k = 0xF /**< 262145 clock periods */
} WDOG_PeriodSel_TypeDef;
#if defined(_WDOG_CTRL_WARNSEL_MASK) \
|| defined(_WDOG_CFG_WARNSEL_MASK)
/** Select Watchdog warning timeout period as percentage of timeout. */
typedef enum {
wdogWarnDisable = 0, /**< Watchdog warning period is disabled. */
wdogWarnTime25pct = 1, /**< Watchdog warning period is 25% of the timeout. */
wdogWarnTime50pct = 2, /**< Watchdog warning period is 50% of the timeout. */
wdogWarnTime75pct = 3, /**< Watchdog warning period is 75% of the timeout. */
} WDOG_WarnSel_TypeDef;
#endif
#if defined(_WDOG_CTRL_WINSEL_MASK) \
|| defined(_WDOG_CFG_WINSEL_MASK)
/** Select Watchdog illegal window limit. */
typedef enum {
wdogIllegalWindowDisable = 0, /**< Watchdog illegal window disabled. */
wdogIllegalWindowTime12_5pct = 1, /**< Window timeout is 12.5% of the timeout. */
wdogIllegalWindowTime25_0pct = 2, /**< Window timeout is 25% of the timeout. */
wdogIllegalWindowTime37_5pct = 3, /**< Window timeout is 37.5% of the timeout. */
wdogIllegalWindowTime50_0pct = 4, /**< Window timeout is 50% of the timeout. */
wdogIllegalWindowTime62_5pct = 5, /**< Window timeout is 62.5% of the timeout. */
wdogIllegalWindowTime75_0pct = 6, /**< Window timeout is 75% of the timeout. */
wdogIllegalWindowTime87_5pct = 7, /**< Window timeout is 87.5% of the timeout. */
} WDOG_WinSel_TypeDef;
#endif
/*******************************************************************************
******************************* STRUCTS ***********************************
******************************************************************************/
/** Watchdog initialization structure. */
typedef struct {
/** Enable Watchdog when initialization completed. */
bool enable;
/** Counter keeps running during debug halt. */
bool debugRun;
#if defined(_WDOG_CTRL_CLRSRC_MASK) \
|| defined(_WDOG_CFG_CLRSRC_MASK)
/** Select WDOG clear source:
* False: Write to the clear bit will clear the WDOG counter
* True: Rising edge on the PRS Source 0 will clear the WDOG counter
* */
bool clrSrc;
#endif
#if defined(_WDOG_CFG_EM1RUN_MASK)
/** Counter keeps running when in EM1. Available for series2. */
bool em1Run;
#endif
/** Counter keeps running when in EM2. */
bool em2Run;
/** Counter keeps running when in EM3. */
bool em3Run;
/** Block EMU from entering EM4. */
bool em4Block;
#if defined(_WDOG_CFG_MASK)
/** When set, a PRS Source 0 missing event will trigger a WDOG reset. */
bool prs0MissRstEn;
/** When set, a PRS Source 1 missing event will trigger a WDOG reset. */
bool prs1MissRstEn;
#endif
/** Block SW from disabling LFRCO/LFXO oscillators. */
#if defined(_WDOG_CTRL_SWOSCBLOCK_MASK)
bool swoscBlock;
#endif
/** Block SW from modifying the configuration (a reset is needed to reconfigure). */
bool lock;
/** Clock source to use for Watchdog. */
#if defined(_WDOG_CTRL_CLKSEL_MASK)
WDOG_ClkSel_TypeDef clkSel;
#endif
/** Watchdog timeout period. */
WDOG_PeriodSel_TypeDef perSel;
#if defined(_WDOG_CTRL_WARNSEL_MASK) \
|| defined(_WDOG_CFG_WARNSEL_MASK)
/** Select warning time as % of the Watchdog timeout */
WDOG_WarnSel_TypeDef warnSel;
#endif
#if defined(_WDOG_CTRL_WINSEL_MASK) \
|| defined(_WDOG_CFG_WINSEL_MASK)
/** Select illegal window time as % of the Watchdog timeout */
WDOG_WinSel_TypeDef winSel;
#endif
#if defined(_WDOG_CTRL_WDOGRSTDIS_MASK) \
|| defined(_WDOG_CFG_WDOGRSTDIS_MASK)
/** Disable Watchdog reset output if true */
bool resetDisable;
#endif
} WDOG_Init_TypeDef;
/** Suggested default configuration for WDOG initialization structure. */
#if defined(_WDOG_CFG_MASK) && defined(_WDOG_CFG_EM1RUN_MASK)
#define WDOG_INIT_DEFAULT \
{ \
true, /* Start Watchdog when initialization is done. */ \
false, /* WDOG is not counting during debug halt. */ \
false, /* The clear bit will clear the WDOG counter. */ \
false, /* WDOG is not counting when in EM1. */ \
false, /* WDOG is not counting when in EM2. */ \
false, /* WDOG is not counting when in EM3. */ \
false, /* EM4 can be entered. */ \
false, /* PRS Source 0 missing event will not trigger a WDOG reset. */ \
false, /* PRS Source 1 missing event will not trigger a WDOG reset. */ \
false, /* Do not lock WDOG configuration. */ \
wdogPeriod_256k, /* Set longest possible timeout period. */ \
wdogWarnDisable, /* Disable warning interrupt. */ \
wdogIllegalWindowDisable, /* Disable illegal window interrupt. */ \
false /* Do not disable reset. */ \
}
#elif defined(_WDOG_CFG_MASK)
#define WDOG_INIT_DEFAULT \
{ \
true, /* Start Watchdog when initialization is done. */ \
false, /* WDOG is not counting during debug halt. */ \
false, /* The clear bit will clear the WDOG counter. */ \
false, /* WDOG is not counting when in EM2. */ \
false, /* WDOG is not counting when in EM3. */ \
false, /* EM4 can be entered. */ \
false, /* PRS Source 0 missing event will not trigger a WDOG reset. */ \
false, /* PRS Source 1 missing event will not trigger a WDOG reset. */ \
false, /* Do not lock WDOG configuration. */ \
wdogPeriod_256k, /* Set longest possible timeout period. */ \
wdogWarnDisable, /* Disable warning interrupt. */ \
wdogIllegalWindowDisable, /* Disable illegal window interrupt. */ \
false /* Do not disable reset. */ \
}
#elif defined(_WDOG_CTRL_WARNSEL_MASK) \
&& defined(_WDOG_CTRL_WDOGRSTDIS_MASK) \
&& defined(_WDOG_CTRL_WINSEL_MASK)
#define WDOG_INIT_DEFAULT \
{ \
true, /* Start Watchdog when initialization is done. */ \
false, /* WDOG is not counting during debug halt. */ \
false, /* The clear bit will clear the WDOG counter. */ \
false, /* WDOG is not counting when in EM2. */ \
false, /* WDOG is not counting when in EM3. */ \
false, /* EM4 can be entered. */ \
false, /* Do not block disabling LFRCO/LFXO in CMU. */ \
false, /* Do not lock WDOG configuration. */ \
wdogClkSelLFRCO, /* Select 32.768 kHZ WDOG oscillator. */ \
wdogPeriod_256k, /* Set longest possible timeout period. */ \
wdogWarnDisable, /* Disable warning interrupt. */ \
wdogIllegalWindowDisable, /* Disable illegal window interrupt. */ \
false /* Do not disable reset. */ \
}
#else
#define WDOG_INIT_DEFAULT \
{ \
true, /* Start Watchdog when initialization is done. */ \
false, /* WDOG is not counting during debug halt. */ \
false, /* WDOG is not counting when in EM2. */ \
false, /* WDOG is not counting when in EM3. */ \
false, /* EM4 can be entered. */ \
false, /* Do not block disabling LFRCO/LFXO in CMU. */ \
false, /* Do not lock WDOG configuration. */ \
wdogClkSelLFRCO, /* Select 32.768 kHz WDOG oscillator. */ \
wdogPeriod_256k /* Set longest possible timeout period. */ \
}
#endif
/*******************************************************************************
***************************** PROTOTYPES **********************************
******************************************************************************/
void WDOGn_Enable(WDOG_TypeDef *wdog, bool enable);
void WDOGn_Feed(WDOG_TypeDef *wdog);
void WDOGn_Init(WDOG_TypeDef *wdog, const WDOG_Init_TypeDef *init);
void WDOGn_Lock(WDOG_TypeDef *wdog);
void WDOGn_SyncWait(WDOG_TypeDef *wdog);
void WDOGn_Unlock(WDOG_TypeDef *wdog);
#if defined(_WDOG_IF_MASK)
/***************************************************************************//**
* @brief
* Clear one or more pending WDOG interrupts.
*
* @param[in] wdog
* Pointer to the WDOG peripheral register block.
*
* @param[in] flags
* WDOG interrupt sources to clear. Use a set of interrupt flags OR-ed
* together to clear multiple interrupt sources.
******************************************************************************/
__STATIC_INLINE void WDOGn_IntClear(WDOG_TypeDef *wdog, uint32_t flags)
{
#if defined(WDOG_HAS_SET_CLEAR)
wdog->IF_CLR = flags;
#else
wdog->IFC = flags;
#endif
}
/***************************************************************************//**
* @brief
* Disable one or more WDOG interrupts.
*
* @param[in] wdog
* Pointer to the WDOG peripheral register block.
*
* @param[in] flags
* WDOG interrupt sources to disable. Use a set of interrupt flags OR-ed
* together to disable multiple interrupt.
******************************************************************************/
__STATIC_INLINE void WDOGn_IntDisable(WDOG_TypeDef *wdog, uint32_t flags)
{
#if defined(WDOG_HAS_SET_CLEAR)
wdog->IEN_CLR = flags;
#else
wdog->IEN &= ~flags;
#endif
}
/***************************************************************************//**
* @brief
* Enable one or more WDOG interrupts.
*
* @note
* Depending on the use, a pending interrupt may already be set prior to
* enabling the interrupt. To ignore a pending interrupt, consider using
* WDOG_IntClear() prior to enabling the interrupt.
*
* @param[in] wdog
* Pointer to the WDOG peripheral register block.
*
* @param[in] flags
* WDOG interrupt sources to enable. Use a set of interrupt flags OR-ed
* together to set multiple interrupt.
******************************************************************************/
__STATIC_INLINE void WDOGn_IntEnable(WDOG_TypeDef *wdog, uint32_t flags)
{
#if defined(WDOG_HAS_SET_CLEAR)
wdog->IEN_SET = flags;
#else
wdog->IEN |= flags;
#endif
}
/***************************************************************************//**
* @brief
* Get pending WDOG interrupt flags.
*
* @note
* The event bits are not cleared by the use of this function.
*
* @param[in] wdog
* Pointer to the WDOG peripheral register block.
*
* @return
* Pending WDOG interrupt sources. Returns a set of interrupt flags OR-ed
* together for the interrupt sources set.
******************************************************************************/
__STATIC_INLINE uint32_t WDOGn_IntGet(WDOG_TypeDef *wdog)
{
return wdog->IF;
}
/***************************************************************************//**
* @brief
* Get enabled and pending WDOG interrupt flags.
*
* @details
* Useful for handling more interrupt sources in the same interrupt handler.
*
* @param[in] wdog
* Pointer to the WDOG peripheral register block.
*
* @return
* Pending and enabled WDOG interrupt sources. Returns a set of interrupt
* flags OR-ed together for the interrupt sources set.
******************************************************************************/
__STATIC_INLINE uint32_t WDOGn_IntGetEnabled(WDOG_TypeDef *wdog)
{
uint32_t tmp;
tmp = wdog->IEN;
/* Bitwise AND of pending and enabled interrupt flags. */
return wdog->IF & tmp;
}
/***************************************************************************//**
* @brief
* Set one or more pending WDOG interrupts from SW.
*
* @param[in] wdog
* Pointer to the WDOG peripheral register block.
*
* @param[in] flags
* WDOG interrupt sources to set to pending. Use a set of interrupt flags
* (WDOG_IFS_nnn).
******************************************************************************/
__STATIC_INLINE void WDOGn_IntSet(WDOG_TypeDef *wdog, uint32_t flags)
{
#if defined(WDOG_HAS_SET_CLEAR)
wdog->IF_SET = flags;
#else
wdog->IFS = flags;
#endif
}
#endif
/***************************************************************************//**
* @brief
* Get enabled status of the Watchdog.
*
* @param[in] wdog
* Pointer to the WDOG peripheral register block.
*
* @return
* True if Watchdog is enabled.
******************************************************************************/
__STATIC_INLINE bool WDOGn_IsEnabled(WDOG_TypeDef *wdog)
{
#if defined(_WDOG_EN_MASK)
return (wdog->EN & _WDOG_EN_EN_MASK) == WDOG_EN_EN;
#else
return (wdog->CTRL & _WDOG_CTRL_EN_MASK) == WDOG_CTRL_EN;
#endif
}
/***************************************************************************//**
* @brief
* Get locked status of the Watchdog.
*
* @param[in] wdog
* Pointer to the WDOG peripheral register block.
*
* @return
* True if Watchdog is locked.
******************************************************************************/
__STATIC_INLINE bool WDOGn_IsLocked(WDOG_TypeDef *wdog)
{
#if defined(_WDOG_STATUS_MASK)
return (wdog->STATUS & _WDOG_STATUS_LOCK_MASK) == WDOG_STATUS_LOCK_LOCKED;
#else
return (wdog->CTRL & _WDOG_CTRL_LOCK_MASK) == WDOG_CTRL_LOCK;
#endif
}
/** @} (end addtogroup wdog) */
#ifdef __cplusplus
}
#endif
#endif /* defined(WDOG_COUNT) && (WDOG_COUNT > 0) */
#endif /* EM_WDOG_H */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,709 @@
/***************************************************************************//**
* @file
* @brief Analog Comparator (ACMP) Peripheral API
*******************************************************************************
* # License
* <b>Copyright 2018 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* 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_acmp.h"
#if defined(ACMP_COUNT) && (ACMP_COUNT > 0)
#include <stdbool.h>
#include "em_bus.h"
#include "sl_assert.h"
#include "em_gpio.h"
/***************************************************************************//**
* @addtogroup acmp ACMP - Analog Comparator
* @brief Analog comparator (ACMP) Peripheral API
*
* @details
* The Analog Comparator is used to compare voltage of two analog inputs
* with a digital output indicating which input voltage is higher. Inputs can
* either be one of the selectable internal references or from external pins.
* Response time and current consumption can be configured by
* altering the current supply to the comparator.
*
* ACMP is available down to EM3 and is able to wake up the system when
* input signals pass a certain threshold. Use @ref ACMP_IntEnable() to enable
* an edge interrupt to use this functionality.
*
* This example shows how to use the em_acmp.h API for comparing an input
* pin to an internal 2.5 V reference voltage.
*
* @if DOXYDOC_P1_DEVICE
* @include em_acmp_compare_s0.c
* @endif
*
* @if DOXYDOC_P2_DEVICE
* @include em_acmp_compare_s1.c
* @endif
*
* @if DOXYDOC_S2_DEVICE
* @include em_acmp_compare_s2.c
* @endif
*
* @note
* ACMP can also be used to compare two separate input pins.
*
* @details
* ACMP also contains specialized hardware for capacitive sensing. This
* module contains the @ref ACMP_CapsenseInit() function to initialize
* ACMP for capacitive sensing and the @ref ACMP_CapsenseChannelSet() function
* to select the current capsense channel.
*
* For applications that require capacitive sensing it is recommended to use a
* library, such as cslib, which is provided by Silicon Labs.
*
* @{
******************************************************************************/
/*******************************************************************************
******************************* DEFINES ***********************************
******************************************************************************/
/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
/** Validation of ACMP register block pointer reference
* for assert statements. */
#if (ACMP_COUNT == 1)
#define ACMP_REF_VALID(ref) ((ref) == ACMP0)
#elif (ACMP_COUNT == 2)
#define ACMP_REF_VALID(ref) (((ref) == ACMP0) || ((ref) == ACMP1))
#elif (ACMP_COUNT == 3)
#define ACMP_REF_VALID(ref) (((ref) == ACMP0) || ((ref) == ACMP1) || ((ref) == ACMP2))
#elif (ACMP_COUNT == 4)
#define ACMP_REF_VALID(ref) (((ref) == ACMP0) \
|| ((ref) == ACMP1) \
|| ((ref) == ACMP2) \
|| ((ref) == ACMP3))
#else
#error Undefined number of analog comparators (ACMP).
#endif
/** The maximum value that can be inserted in the route location register
* for the specific device. */
#if defined(_ACMP_ROUTE_LOCATION_LOC3)
#define _ACMP_ROUTE_LOCATION_MAX _ACMP_ROUTE_LOCATION_LOC3
#elif defined(_ACMP_ROUTE_LOCATION_LOC2)
#define _ACMP_ROUTE_LOCATION_MAX _ACMP_ROUTE_LOCATION_LOC2
#elif defined(_ACMP_ROUTE_LOCATION_LOC1)
#define _ACMP_ROUTE_LOCATION_MAX _ACMP_ROUTE_LOCATION_LOC1
#elif defined(_ACMP_ROUTELOC0_OUTLOC_LOC31)
#define _ACMP_ROUTE_LOCATION_MAX _ACMP_ROUTELOC0_OUTLOC_LOC31
#elif defined(_ACMP_ROUTELOC0_OUTLOC_MASK)
#define _ACMP_ROUTE_LOCATION_MAX _ACMP_ROUTELOC0_OUTLOC_MASK
#endif
/** Map ACMP reference to index of device. */
#if (ACMP_COUNT == 1)
#define ACMP_DEVICE_ID(acmp) ( \
(acmp) == ACMP0 ? 0 \
: 0)
#elif (ACMP_COUNT == 2)
#define ACMP_DEVICE_ID(acmp) ( \
(acmp) == ACMP0 ? 0 \
: (acmp) == ACMP1 ? 1 \
: 0)
#endif
/** @endcond */
/*******************************************************************************
************************** GLOBAL FUNCTIONS *******************************
******************************************************************************/
/***************************************************************************//**
* @brief
* Set up ACMP for use in capacitive sense applications.
*
* @details
* This function sets up ACMP for use in capacitive sense applications.
* To use the capacitive sense functionality in the ACMP, use
* the PRS output of the ACMP module to count the number of oscillations
* in the capacitive sense circuit (possibly using a TIMER).
*
* @note
* A basic example of capacitive sensing can be found in the STK BSP
* (capsense demo).
*
* @cond DOXYDOC_S2_DEVICE
* @note
* A call to ACMP_CapsenseInit will enable and disable the ACMP peripheral,
* which can cause side effects if it was previously set up.
* @endcond
*
* @param[in] acmp
* A pointer to the ACMP peripheral register block.
*
* @param[in] init
* A pointer to the initialization structure used to configure ACMP for capacitive
* sensing operation.
******************************************************************************/
void ACMP_CapsenseInit(ACMP_TypeDef *acmp, const ACMP_CapsenseInit_TypeDef *init)
{
EFM_ASSERT(ACMP_REF_VALID(acmp));
#if defined(_SILICON_LABS_32B_SERIES_2)
EFM_ASSERT(init->vrefDiv < 64);
EFM_ASSERT(init->biasProg
<= (_ACMP_CFG_BIAS_MASK >> _ACMP_CFG_BIAS_SHIFT));
ACMP_Disable(acmp);
acmp->CFG = (init->biasProg << _ACMP_CFG_BIAS_SHIFT)
| (init->hysteresisLevel << _ACMP_CFG_HYST_SHIFT);
acmp->CTRL = _ACMP_CTRL_RESETVALUE;
ACMP_Enable(acmp);
acmp->INPUTCTRL = (init->resistor << _ACMP_INPUTCTRL_CSRESSEL_SHIFT)
| (init->vrefDiv << _ACMP_INPUTCTRL_VREFDIV_SHIFT)
| (ACMP_INPUTCTRL_NEGSEL_CAPSENSE);
if (!init->enable) {
ACMP_Disable(acmp);
}
#elif defined(_SILICON_LABS_32B_SERIES_1)
EFM_ASSERT(init->vddLevelLow < 64);
EFM_ASSERT(init->vddLevelHigh < 64);
EFM_ASSERT(init->biasProg
<= (_ACMP_CTRL_BIASPROG_MASK >> _ACMP_CTRL_BIASPROG_SHIFT));
/* Set the control register. No need to set interrupt modes. */
acmp->CTRL = (init->fullBias << _ACMP_CTRL_FULLBIAS_SHIFT)
| (init->biasProg << _ACMP_CTRL_BIASPROG_SHIFT)
| ACMP_CTRL_ACCURACY_HIGH;
acmp->HYSTERESIS0 = (init->vddLevelHigh << _ACMP_HYSTERESIS0_DIVVA_SHIFT)
| (init->hysteresisLevel_0 << _ACMP_HYSTERESIS0_HYST_SHIFT);
acmp->HYSTERESIS1 = (init->vddLevelLow << _ACMP_HYSTERESIS1_DIVVA_SHIFT)
| (init->hysteresisLevel_1 << _ACMP_HYSTERESIS1_HYST_SHIFT);
/* Select capacitive sensing mode by selecting a resistor and enabling it. */
acmp->INPUTSEL = (init->resistor << _ACMP_INPUTSEL_CSRESSEL_SHIFT)
| ACMP_INPUTSEL_CSRESEN
| ACMP_INPUTSEL_VASEL_VDD
| ACMP_INPUTSEL_NEGSEL_VADIV;
BUS_RegBitWrite(&acmp->CTRL, _ACMP_CTRL_EN_SHIFT, init->enable);
#elif defined(_SILICON_LABS_32B_SERIES_0)
EFM_ASSERT(init->vddLevel < 64);
EFM_ASSERT(init->biasProg
<= (_ACMP_CTRL_BIASPROG_MASK >> _ACMP_CTRL_BIASPROG_SHIFT));
/* Set the control register. No need to set interrupt modes. */
acmp->CTRL = (init->fullBias << _ACMP_CTRL_FULLBIAS_SHIFT)
| (init->halfBias << _ACMP_CTRL_HALFBIAS_SHIFT)
| (init->biasProg << _ACMP_CTRL_BIASPROG_SHIFT)
| (init->warmTime << _ACMP_CTRL_WARMTIME_SHIFT)
| (init->hysteresisLevel << _ACMP_CTRL_HYSTSEL_SHIFT);
/* Select capacitive sensing mode by selecting a resistor and enabling it. */
acmp->INPUTSEL = (init->resistor << _ACMP_INPUTSEL_CSRESSEL_SHIFT)
| ACMP_INPUTSEL_CSRESEN
| (init->lowPowerReferenceEnabled << _ACMP_INPUTSEL_LPREF_SHIFT)
| (init->vddLevel << _ACMP_INPUTSEL_VDDLEVEL_SHIFT)
| ACMP_INPUTSEL_NEGSEL_CAPSENSE;
BUS_RegBitWrite(&acmp->CTRL, _ACMP_CTRL_EN_SHIFT, init->enable);
#endif
}
/***************************************************************************//**
* @brief
* Set the ACMP channel used for capacitive sensing.
*
* @note
* A basic example of capacitive sensing can be found in the STK BSP
* (capsense demo).
*
* @cond DOXYDOC_S2_DEVICE
* @note
* Can only be called when the peripheral is enabled.
* @endcond
*
* @param[in] acmp
* A pointer to the ACMP peripheral register block.
*
* @param[in] channel
* The ACMP channel to use for capacitive sensing (Possel).
******************************************************************************/
void ACMP_CapsenseChannelSet(ACMP_TypeDef *acmp, ACMP_Channel_TypeDef channel)
{
/* Make sure the module exists on the selected chip. */
EFM_ASSERT(ACMP_REF_VALID(acmp));
#if defined(_ACMP_INPUTSEL_POSSEL_CH7)
/* Make sure that only external channels are used. */
EFM_ASSERT(channel <= _ACMP_INPUTSEL_POSSEL_CH7);
#elif defined(_ACMP_INPUTCTRL_POSSEL_PD15)
EFM_ASSERT(channel != _ACMP_INPUTCTRL_NEGSEL_CAPSENSE);
EFM_ASSERT(_ACMP_INPUTCTRL_POSSEL_PA0 <= channel);
EFM_ASSERT(channel <= _ACMP_INPUTCTRL_POSSEL_PD15);
#endif
#if defined(_ACMP_INPUTCTRL_MASK)
/* Make sure that the ACMP is enabled before changing INPUTCTRL. */
EFM_ASSERT(acmp->EN & ACMP_EN_EN);
while (acmp->SYNCBUSY != 0U) {
/* Wait for synchronization to finish */
}
/* Set channel as positive channel in ACMP */
BUS_RegMaskedWrite(&acmp->INPUTCTRL, _ACMP_INPUTCTRL_POSSEL_MASK,
channel << _ACMP_INPUTCTRL_POSSEL_SHIFT);
#else
/* Set channel as a positive channel in ACMP. */
BUS_RegMaskedWrite(&acmp->INPUTSEL, _ACMP_INPUTSEL_POSSEL_MASK,
channel << _ACMP_INPUTSEL_POSSEL_SHIFT);
#endif
}
/***************************************************************************//**
* @brief
* Disable ACMP.
*
* @param[in] acmp
* A pointer to the ACMP peripheral register block.
******************************************************************************/
void ACMP_Disable(ACMP_TypeDef *acmp)
{
/* Make sure the module exists on the selected chip. */
EFM_ASSERT(ACMP_REF_VALID(acmp));
#if defined(_ACMP_EN_MASK)
while ((acmp->EN != 0U) && (acmp->SYNCBUSY != 0U)) {
/* Wait for synchronization to finish */
}
acmp->EN_CLR = ACMP_EN_EN;
#if defined(_ACMP_EN_DISABLING_MASK)
while (acmp->EN & _ACMP_EN_DISABLING_MASK) {
// Wait for disabling to finish
}
#endif
#else
acmp->CTRL &= ~ACMP_CTRL_EN;
#endif
}
/***************************************************************************//**
* @brief
* Enable ACMP.
*
* @param[in] acmp
* A pointer to the ACMP peripheral register block.
******************************************************************************/
void ACMP_Enable(ACMP_TypeDef *acmp)
{
/* Make sure the module exists on the selected chip. */
EFM_ASSERT(ACMP_REF_VALID(acmp));
#if defined(_ACMP_EN_MASK)
acmp->EN_SET = ACMP_EN_EN;
#else
acmp->CTRL |= ACMP_CTRL_EN;
#endif
}
#if defined(_ACMP_EXTIFCTRL_MASK)
/***************************************************************************//**
* @brief
* Select and enable external input.
*
* @details
* This is used when an external module needs to take control of the ACMP
* POSSEL field to configure the APORT input for the ACMP. Modules,
* such as LESENSE, use this to change the ACMP input during a scan sequence.
*
* @param[in] acmp
* A pointer to the ACMP peripheral register block.
*
* @param[in] aport
* This parameter decides which APORT(s) the ACMP will use when it's
* controlled by an external module.
******************************************************************************/
void ACMP_ExternalInputSelect(ACMP_TypeDef *acmp, ACMP_ExternalInput_Typedef aport)
{
acmp->EXTIFCTRL = (aport << _ACMP_EXTIFCTRL_APORTSEL_SHIFT)
| ACMP_EXTIFCTRL_EN;
while (!(acmp->STATUS & ACMP_STATUS_EXTIFACT)) {
}
}
#endif
/***************************************************************************//**
* @brief
* Reset ACMP to the same state that it was in after a hardware reset.
*
* @note
* The GPIO ACMP ROUTE register is NOT reset by this function to allow for
* centralized setup of this feature.
*
* @note
* The peripheral may be enabled and disabled during reset.
*
* @param[in] acmp
* A pointer to the ACMP peripheral register block.
******************************************************************************/
void ACMP_Reset(ACMP_TypeDef *acmp)
{
/* Make sure the module exists on the selected chip */
EFM_ASSERT(ACMP_REF_VALID(acmp));
#if defined(_SILICON_LABS_32B_SERIES_2)
#if defined(ACMP_SWRST_SWRST)
acmp->SWRST_SET = ACMP_SWRST_SWRST;
while (acmp->SWRST & _ACMP_SWRST_RESETTING_MASK) {
}
#else
acmp->IEN = _ACMP_IEN_RESETVALUE;
ACMP_Enable(acmp);
acmp->INPUTCTRL = _ACMP_INPUTCTRL_RESETVALUE;
ACMP_Disable(acmp);
acmp->CFG = PM5507_ACMP_CFG_RESETVALUE;
acmp->CTRL = _ACMP_CTRL_RESETVALUE;
acmp->IF_CLR = _ACMP_IF_MASK;
#endif
#else // Series 0 and Series 1 devices
acmp->IEN = _ACMP_IEN_RESETVALUE;
acmp->CTRL = _ACMP_CTRL_RESETVALUE;
acmp->INPUTSEL = _ACMP_INPUTSEL_RESETVALUE;
#if defined(_ACMP_HYSTERESIS0_HYST_MASK)
acmp->HYSTERESIS0 = _ACMP_HYSTERESIS0_RESETVALUE;
acmp->HYSTERESIS1 = _ACMP_HYSTERESIS1_RESETVALUE;
#endif
acmp->IFC = _ACMP_IF_MASK;
#endif
}
#if defined(_GPIO_ACMP_ROUTEEN_MASK)
/***************************************************************************//**
* @brief
* Sets up GPIO output from the ACMP.
*
* @note
* GPIO must be enabled in the CMU before this function call, i.e.
* @verbatim CMU_ClockEnable(cmuClock_GPIO, true); @endverbatim
*
* @param[in] acmp
* Pointer to the ACMP peripheral register block.
*
* @param port
* The GPIO port to use.
*
* @param pin
* The GPIO pin to use.
*
* @param enable
* Enable or disable pin output.
*
* @param invert
* Invert output.
******************************************************************************/
void ACMP_GPIOSetup(ACMP_TypeDef *acmp, GPIO_Port_TypeDef port,
unsigned int pin, bool enable, bool invert)
{
int acmpIndex = ACMP_DEVICE_ID(acmp);
/* Make sure the module exists on the selected chip */
EFM_ASSERT(ACMP_REF_VALID(acmp));
/* Make sure that the port/pin combination is valid. */
EFM_ASSERT(GPIO_PORT_PIN_VALID(port, pin));
/* Set GPIO inversion */
acmp->CTRL = (acmp->CTRL & _ACMP_CTRL_NOTRDYVAL_MASK)
| (invert << _ACMP_CTRL_GPIOINV_SHIFT);
GPIO->ACMPROUTE[acmpIndex].ACMPOUTROUTE = (port << _GPIO_ACMP_ACMPOUTROUTE_PORT_SHIFT)
| (pin << _GPIO_ACMP_ACMPOUTROUTE_PIN_SHIFT);
GPIO->ACMPROUTE[acmpIndex].ROUTEEN = enable ? GPIO_ACMP_ROUTEEN_ACMPOUTPEN : 0;
}
#else
/***************************************************************************//**
* @brief
* Set up GPIO output from ACMP.
*
* @note
* GPIO must be enabled in the CMU before this function call, i.e.,
* @verbatim CMU_ClockEnable(cmuClock_GPIO, true); @endverbatim
*
* @param[in] acmp
* A pointer to the ACMP peripheral register block.
*
* @param location
* The pin location to use. See the data sheet for location to pin mappings.
*
* @param enable
* Enable or disable pin output.
*
* @param invert
* Invert output.
******************************************************************************/
void ACMP_GPIOSetup(ACMP_TypeDef *acmp, uint32_t location, bool enable, bool invert)
{
/* Make sure the module exists on the selected chip */
EFM_ASSERT(ACMP_REF_VALID(acmp));
/* Sanity checking of location */
EFM_ASSERT(location <= _ACMP_ROUTE_LOCATION_MAX);
/* Set GPIO inversion */
BUS_RegMaskedWrite(&acmp->CTRL, _ACMP_CTRL_GPIOINV_MASK,
invert << _ACMP_CTRL_GPIOINV_SHIFT);
#if defined(_ACMP_ROUTE_MASK)
acmp->ROUTE = (location << _ACMP_ROUTE_LOCATION_SHIFT)
| (enable << _ACMP_ROUTE_ACMPPEN_SHIFT);
#endif
#if defined(_ACMP_ROUTELOC0_MASK)
acmp->ROUTELOC0 = location << _ACMP_ROUTELOC0_OUTLOC_SHIFT;
acmp->ROUTEPEN = enable ? ACMP_ROUTEPEN_OUTPEN : 0;
#endif
}
#endif /* defined(_GPIO_ACMP_ROUTEEN_MASK) */
/***************************************************************************//**
* @brief
* Set which channels should be used in ACMP comparisons.
*
* @cond DOXYDOC_S2_DEVICE
* @note
* Can only be called when the peripheral is enabled.
*
* @note
* If GPIO is used for both posSel and negSel, they cannot both use even
* or odd pins.
* @endcond
*
* @param[in] acmp
* A pointer to the ACMP peripheral register block.
*
* @param negSel
* A channel to use on the negative input to the ACMP.
*
* @param posSel
* A channel to use on the positive input to the ACMP.
******************************************************************************/
void ACMP_ChannelSet(ACMP_TypeDef *acmp, ACMP_Channel_TypeDef negSel,
ACMP_Channel_TypeDef posSel)
{
/* Make sure the module exists on the selected chip. */
EFM_ASSERT(ACMP_REF_VALID(acmp));
/* Make sure that posSel and negSel channel selectors are valid. */
#if defined(_ACMP_INPUTSEL_NEGSEL_DAC0CH1)
EFM_ASSERT(negSel <= _ACMP_INPUTSEL_NEGSEL_DAC0CH1);
#elif defined(_ACMP_INPUTSEL_NEGSEL_CAPSENSE)
EFM_ASSERT(negSel <= _ACMP_INPUTSEL_NEGSEL_CAPSENSE);
#endif
#if defined(_ACMP_INPUTSEL_POSSEL_CH7)
EFM_ASSERT(posSel <= _ACMP_INPUTSEL_POSSEL_CH7);
#endif
/* Make sure that posSel and negSel channel selectors are valid. */
#if defined(_ACMP_INPUTCTRL_POSSEL_PD15)
EFM_ASSERT(negSel <= _ACMP_INPUTCTRL_POSSEL_PD15);
EFM_ASSERT(posSel <= _ACMP_INPUTCTRL_POSSEL_PD15);
EFM_ASSERT(posSel != _ACMP_INPUTCTRL_NEGSEL_CAPSENSE);
/* Make sure that posSel and negSel channel selectors don't both
* use odd or even pins. */
#if (_SILICON_LABS_32B_SERIES_2_CONFIG > 2)
EFM_ASSERT(!((((posSel >= _ACMP_INPUTCTRL_POSSEL_EXTPA)
&& (posSel <= _ACMP_INPUTCTRL_POSSEL_EXTPD))
|| (posSel >= _ACMP_INPUTCTRL_POSSEL_PA0))
&& (negSel >= _ACMP_INPUTCTRL_NEGSEL_PA0)
&& (posSel % 2 == negSel % 2)));
#else
EFM_ASSERT(!((posSel >= _ACMP_INPUTCTRL_POSSEL_PA0)
&& (negSel >= _ACMP_INPUTCTRL_NEGSEL_PA0)
&& (posSel % 2 == negSel % 2)));
#endif
#endif
#if defined(_ACMP_INPUTCTRL_MASK)
/* Make sure that the ACMP is enabled before changing INPUTCTRL. */
EFM_ASSERT(acmp->EN & ACMP_EN_EN);
while (acmp->SYNCBUSY != 0U) {
/* Wait for synchronization to finish */
}
acmp->INPUTCTRL = (acmp->INPUTCTRL & ~(_ACMP_INPUTCTRL_POSSEL_MASK
| _ACMP_INPUTCTRL_NEGSEL_MASK))
| (negSel << _ACMP_INPUTCTRL_NEGSEL_SHIFT)
| (posSel << _ACMP_INPUTCTRL_POSSEL_SHIFT);
#else
acmp->INPUTSEL = (acmp->INPUTSEL & ~(_ACMP_INPUTSEL_POSSEL_MASK
| _ACMP_INPUTSEL_NEGSEL_MASK))
| (negSel << _ACMP_INPUTSEL_NEGSEL_SHIFT)
| (posSel << _ACMP_INPUTSEL_POSSEL_SHIFT);
#endif
}
/***************************************************************************//**
* @brief
* Initialize ACMP.
*
* @cond DOXYDOC_S2_DEVICE
* @note
* A call to ACMP_Init can cause side effects since it can enable/disable
* the peripheral.
* @endcond
*
* @param[in] acmp
* A pointer to the ACMP peripheral register block.
*
* @param[in] init
* A pointer to the initialization structure used to configure ACMP.
******************************************************************************/
void ACMP_Init(ACMP_TypeDef *acmp, const ACMP_Init_TypeDef *init)
{
/* Make sure the module exists on the selected chip. */
EFM_ASSERT(ACMP_REF_VALID(acmp));
#if defined(_SILICON_LABS_32B_SERIES_2)
EFM_ASSERT(init->biasProg
<= (_ACMP_CFG_BIAS_MASK >> _ACMP_CFG_BIAS_SHIFT));
// PM-5507: enforce that biasProg is a functional value
#if defined(_SILICON_LABS_32B_SERIES_2_CONFIG_1)
EFM_ASSERT(init->biasProg >= 4);
#elif defined(_SILICON_LABS_32B_SERIES_2_CONFIG_3)
// Allow customer to use BIASPROG in [2; 3]
EFM_ASSERT(init->biasProg >= 2);
#else
// Allow customer to use BIASPROG in [0; 3]
// but the implementation of the wait operation would be their responsibility
#endif
/* Make sure the ACMP is disabled since ACMP power source might be changed.*/
ACMP_Disable(acmp);
acmp->CFG = (init->biasProg << _ACMP_CFG_BIAS_SHIFT)
| (init->inputRange << _ACMP_CFG_INPUTRANGE_SHIFT)
| (init->accuracy << _ACMP_CFG_ACCURACY_SHIFT)
| (init->hysteresisLevel << _ACMP_CFG_HYST_SHIFT);
acmp->CTRL = init->inactiveValue << _ACMP_CTRL_NOTRDYVAL_SHIFT;
ACMP_Enable(acmp);
BUS_RegMaskedWrite(&acmp->INPUTCTRL, _ACMP_INPUTCTRL_VREFDIV_MASK,
init->vrefDiv << _ACMP_INPUTCTRL_VREFDIV_SHIFT);
#elif defined(_SILICON_LABS_32B_SERIES_1)
EFM_ASSERT(init->biasProg
<= (_ACMP_CTRL_BIASPROG_MASK >> _ACMP_CTRL_BIASPROG_SHIFT));
/* Make sure the ACMP is disabled since ACMP power source might be changed.*/
ACMP_Disable(acmp);
acmp->CTRL = (init->fullBias << _ACMP_CTRL_FULLBIAS_SHIFT)
| (init->biasProg << _ACMP_CTRL_BIASPROG_SHIFT)
| (init->interruptOnFallingEdge << _ACMP_CTRL_IFALL_SHIFT)
| (init->interruptOnRisingEdge << _ACMP_CTRL_IRISE_SHIFT)
| (init->inputRange << _ACMP_CTRL_INPUTRANGE_SHIFT)
| (init->accuracy << _ACMP_CTRL_ACCURACY_SHIFT)
| (init->powerSource << _ACMP_CTRL_PWRSEL_SHIFT)
| (init->inactiveValue << _ACMP_CTRL_INACTVAL_SHIFT);
acmp->INPUTSEL = init->vlpInput << _ACMP_INPUTSEL_VLPSEL_SHIFT;
acmp->HYSTERESIS0 = init->hysteresisLevel_0;
acmp->HYSTERESIS1 = init->hysteresisLevel_1;
#elif defined(_SILICON_LABS_32B_SERIES_0)
EFM_ASSERT(init->biasProg
<= (_ACMP_CTRL_BIASPROG_MASK >> _ACMP_CTRL_BIASPROG_SHIFT));
/* Make sure the ACMP is disabled since ACMP power source might be changed.*/
ACMP_Disable(acmp);
acmp->CTRL = (init->fullBias << _ACMP_CTRL_FULLBIAS_SHIFT)
| (init->halfBias << _ACMP_CTRL_HALFBIAS_SHIFT)
| (init->biasProg << _ACMP_CTRL_BIASPROG_SHIFT)
| (init->interruptOnFallingEdge << _ACMP_CTRL_IFALL_SHIFT)
| (init->interruptOnRisingEdge << _ACMP_CTRL_IRISE_SHIFT)
| (init->warmTime << _ACMP_CTRL_WARMTIME_SHIFT)
| (init->hysteresisLevel << _ACMP_CTRL_HYSTSEL_SHIFT)
| (init->inactiveValue << _ACMP_CTRL_INACTVAL_SHIFT);
acmp->INPUTSEL = (init->lowPowerReferenceEnabled << _ACMP_INPUTSEL_LPREF_SHIFT)
| (init->vddLevel << _ACMP_INPUTSEL_VDDLEVEL_SHIFT);
#endif
if (init->enable) {
ACMP_Enable(acmp);
} else {
ACMP_Disable(acmp);
}
}
#if defined(_ACMP_INPUTSEL_VASEL_MASK)
/***************************************************************************//**
* @brief
* Set up the VA source.
*
* @param[in] acmp
* A pointer to the ACMP peripheral register block.
*
* @param[in] vaconfig
* A pointer to the structure used to configure the VA source. This structure
* contains the input source and the 2 divider values.
******************************************************************************/
void ACMP_VASetup(ACMP_TypeDef *acmp, const ACMP_VAConfig_TypeDef *vaconfig)
{
EFM_ASSERT(vaconfig->div0 < 64);
EFM_ASSERT(vaconfig->div1 < 64);
BUS_RegMaskedWrite(&acmp->INPUTSEL, _ACMP_INPUTSEL_VASEL_MASK,
vaconfig->input << _ACMP_INPUTSEL_VASEL_SHIFT);
BUS_RegMaskedWrite(&acmp->HYSTERESIS0, _ACMP_HYSTERESIS0_DIVVA_MASK,
vaconfig->div0 << _ACMP_HYSTERESIS0_DIVVA_SHIFT);
BUS_RegMaskedWrite(&acmp->HYSTERESIS1, _ACMP_HYSTERESIS1_DIVVA_MASK,
vaconfig->div1 << _ACMP_HYSTERESIS1_DIVVA_SHIFT);
}
#endif
#if defined(_ACMP_INPUTSEL_VBSEL_MASK)
/***************************************************************************//**
* @brief
* Set up the VB Source.
*
* @param[in] acmp
* A pointer to the ACMP peripheral register block.
*
* @param[in] vbconfig
* A pointer to the structure used to configure the VB source. This structure
* contains the input source and the 2 divider values.
******************************************************************************/
void ACMP_VBSetup(ACMP_TypeDef *acmp, const ACMP_VBConfig_TypeDef *vbconfig)
{
EFM_ASSERT(vbconfig->div0 < 64);
EFM_ASSERT(vbconfig->div1 < 64);
BUS_RegMaskedWrite(&acmp->INPUTSEL, _ACMP_INPUTSEL_VBSEL_MASK,
vbconfig->input << _ACMP_INPUTSEL_VBSEL_SHIFT);
BUS_RegMaskedWrite(&acmp->HYSTERESIS0, _ACMP_HYSTERESIS0_DIVVB_MASK,
vbconfig->div0 << _ACMP_HYSTERESIS0_DIVVB_SHIFT);
BUS_RegMaskedWrite(&acmp->HYSTERESIS1, _ACMP_HYSTERESIS1_DIVVB_MASK,
vbconfig->div1 << _ACMP_HYSTERESIS1_DIVVB_SHIFT);
}
#endif
/** @} (end addtogroup acmp) */
#endif /* defined(ACMP_COUNT) && (ACMP_COUNT > 0) */

View File

@@ -0,0 +1,433 @@
/***************************************************************************//**
* @file
* @brief Backup Real Time Counter (BURTC) Peripheral API
*******************************************************************************
* # License
* <b>Copyright 2018 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* 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_burtc.h"
#if defined(BURTC_PRESENT)
/***************************************************************************//**
* @addtogroup burtc BURTC - Backup RTC
* @brief Backup Real Time Counter (BURTC) Peripheral API
* @details
* This module contains functions to control the BURTC peripheral of Silicon
* Labs 32-bit MCUs. The Backup Real Time Counter allows timekeeping in all
* energy modes. The Backup RTC is also available when the system is in backup
* mode.
* @{
******************************************************************************/
/*******************************************************************************
******************************* DEFINES ***********************************
******************************************************************************/
/*******************************************************************************
************************** LOCAL FUNCTIONS ********************************
******************************************************************************/
/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
/***************************************************************************//**
* @brief Convert dividend to a prescaler logarithmic value. Only works for even
* numbers equal to 2^n.
* @param[in] div Unscaled dividend,
* @return Base 2 logarithm of input, as used by fixed prescalers.
******************************************************************************/
__STATIC_INLINE uint32_t divToLog2(uint32_t div)
{
uint32_t log2;
/* Prescaler accepts an argument of 128 or less, valid values being 2^n. */
EFM_ASSERT((div > 0UL) && (div <= 32768UL));
/* Count leading zeroes and "reverse" result, Cortex-M3 intrinsic. */
log2 = (31UL - __CLZ(div));
return log2;
}
/***************************************************************************//**
* @brief
* Wait for an ongoing sync of register(s) to low frequency domain to complete.
*
* @param[in] mask
* A bitmask corresponding to SYNCBUSY register defined bits, indicating
* registers that must complete any ongoing synchronization.
******************************************************************************/
__STATIC_INLINE void regSync(uint32_t mask)
{
#if defined(_BURTC_FREEZE_MASK)
/* Avoid deadlock if modifying the same register twice when freeze mode is
activated or when a clock is not selected for the BURTC. If a clock is
not selected, then the sync is done once the clock source is set. */
if ((BURTC->FREEZE & BURTC_FREEZE_REGFREEZE)
|| ((BURTC->CTRL & _BURTC_CTRL_CLKSEL_MASK) == BURTC_CTRL_CLKSEL_NONE)
|| ((BURTC->CTRL & _BURTC_CTRL_RSTEN_MASK) == BURTC_CTRL_RSTEN)) {
return;
}
#endif
/* Wait for any pending previous write operation to complete */
/* in low frequency domain. This is only required for the Gecko Family. */
while ((BURTC->SYNCBUSY & mask) != 0U) {
}
}
/** @endcond */
/*******************************************************************************
************************** GLOBAL FUNCTIONS *******************************
******************************************************************************/
/***************************************************************************//**
* @brief Initialize BURTC.
*
* @details
* Configures the BURTC peripheral.
*
* @note
* Before initialization, BURTC module must first be enabled by clearing the
* reset bit in the RMU, i.e.,
* @verbatim
* RMU_ResetControl(rmuResetBU, rmuResetModeClear);
* @endverbatim
* Compare channel 0 must be configured outside this function, before
* initialization if enable is set to true. The counter will always be reset.
*
* @param[in] burtcInit
* A pointer to the BURTC initialization structure.
******************************************************************************/
void BURTC_Init(const BURTC_Init_TypeDef *burtcInit)
{
#if defined(_SILICON_LABS_32B_SERIES_0)
uint32_t ctrl;
uint32_t presc;
/* Check initializer structure integrity. */
EFM_ASSERT(burtcInit != (BURTC_Init_TypeDef *) 0);
/* Clock divider must be between 1 and 128, really on the form 2^n. */
EFM_ASSERT((burtcInit->clkDiv >= 1) && (burtcInit->clkDiv <= 128));
/* Ignored compare bits during low power operation must be less than 7. */
/* Note! Giant Gecko revision C errata, do NOT use LPCOMP=7. */
EFM_ASSERT(burtcInit->lowPowerComp <= 6);
/* You cannot enable the BURTC if mode is set to disabled. */
EFM_ASSERT((burtcInit->enable == false)
|| ((burtcInit->enable == true)
&& (burtcInit->mode != burtcModeDisable)));
/* Low power mode is only available with LFRCO or LFXO as clock source. */
EFM_ASSERT((burtcInit->clkSel != burtcClkSelULFRCO)
|| ((burtcInit->clkSel == burtcClkSelULFRCO)
&& (burtcInit->lowPowerMode == burtcLPDisable)));
/* Calculate a prescaler value from the clock divider input. */
/* Note! If clock select (clkSel) is ULFRCO, a clock divisor (clkDiv) of
value 1 will select a 2 kHz ULFRCO clock, while any other value will
select a 1 kHz ULFRCO clock source. */
presc = divToLog2(burtcInit->clkDiv);
/* Make sure all registers are updated simultaneously. */
if (burtcInit->enable) {
BURTC_FreezeEnable(true);
}
/* Modification of LPMODE register requires sync with potential ongoing
* register updates in LF domain. */
regSync(BURTC_SYNCBUSY_LPMODE);
/* Configure low power mode. */
BURTC->LPMODE = (uint32_t) (burtcInit->lowPowerMode);
/* New configuration. */
ctrl = (BURTC_CTRL_RSTEN
| (burtcInit->mode)
| (burtcInit->debugRun << _BURTC_CTRL_DEBUGRUN_SHIFT)
| (burtcInit->compare0Top << _BURTC_CTRL_COMP0TOP_SHIFT)
| (burtcInit->lowPowerComp << _BURTC_CTRL_LPCOMP_SHIFT)
| (presc << _BURTC_CTRL_PRESC_SHIFT)
| (burtcInit->clkSel)
| (burtcInit->timeStamp << _BURTC_CTRL_BUMODETSEN_SHIFT));
/* Clear interrupts. */
BURTC_IntClear(0xFFFFFFFF);
/* Set the new configuration. */
BURTC->CTRL = ctrl;
/* Enable BURTC and counter. */
if (burtcInit->enable) {
/* To enable BURTC counter, disable reset. */
BURTC_Enable(true);
/* Clear freeze. */
BURTC_FreezeEnable(false);
}
#elif defined(_SILICON_LABS_32B_SERIES_2)
uint32_t presc;
presc = divToLog2(burtcInit->clkDiv);
if (BURTC->EN != 0U) {
BURTC_SyncWait();
}
BURTC->EN_CLR = BURTC_EN_EN;
#if defined(_BURTC_SYNCBUSY_EN_MASK)
regSync(BURTC_SYNCBUSY_EN);
#elif defined(_BURTC_EN_DISABLING_MASK)
while (BURTC->EN & _BURTC_EN_DISABLING_MASK) {
/* Wait for disabling to finish */
}
#endif
BURTC->CFG = (presc << _BURTC_CFG_CNTPRESC_SHIFT)
| ((burtcInit->compare0Top ? 1UL : 0UL) << _BURTC_CFG_COMPTOP_SHIFT)
| ((burtcInit->debugRun ? 1UL : 0UL) << _BURTC_CFG_DEBUGRUN_SHIFT);
BURTC->EM4WUEN = ((burtcInit->em4comp ? 1UL : 0UL) << _BURTC_EM4WUEN_COMPEM4WUEN_SHIFT)
| ((burtcInit->em4overflow ? 1UL : 0UL) << _BURTC_EM4WUEN_OFEM4WUEN_SHIFT);
BURTC->EN_SET = BURTC_EN_EN;
if (burtcInit->start) {
BURTC_Start();
}
#endif
}
#if defined(_SILICON_LABS_32B_SERIES_2)
/***************************************************************************//**
* @brief
* Enable or Disable BURTC peripheral.
*
* @param[in] enable
* true to enable, false to disable.
******************************************************************************/
void BURTC_Enable(bool enable)
{
#if defined(_BURTC_SYNCBUSY_EN_MASK)
regSync(BURTC_SYNCBUSY_EN);
#endif
if ((BURTC->EN == 0U) && !enable) {
/* Trying to disable BURTC when it's already disabled */
return;
}
if (BURTC->EN != 0U) {
/* Modifying the enable bit while synchronization is active will BusFault */
BURTC_SyncWait();
}
if (enable) {
BURTC->EN_SET = BURTC_EN_EN;
} else {
BURTC_Stop();
BURTC_SyncWait(); /* Wait for the stop to synchronize */
BURTC->EN_CLR = BURTC_EN_EN;
#if defined(_BURTC_SYNCBUSY_EN_MASK)
regSync(BURTC_SYNCBUSY_EN);
#elif defined(_BURTC_EN_DISABLING_MASK)
while (BURTC->EN & _BURTC_EN_DISABLING_MASK) {
/* Wait for disabling to finish */
}
#endif
}
}
#elif defined(_SILICON_LABS_32B_SERIES_0)
/***************************************************************************//**
* @brief
* Enable or Disable BURTC peripheral reset and start counter
* @param[in] enable
* If true; asserts reset to BURTC, halts counter, if false; deassert reset
******************************************************************************/
void BURTC_Enable(bool enable)
{
/* Note! If mode is disabled, BURTC counter will not start */
EFM_ASSERT(((enable == true)
&& ((BURTC->CTRL & _BURTC_CTRL_MODE_MASK)
!= BURTC_CTRL_MODE_DISABLE))
|| (enable == false));
BUS_RegBitWrite(&BURTC->CTRL, _BURTC_CTRL_RSTEN_SHIFT, (uint32_t) !enable);
}
#endif
/***************************************************************************//**
* @brief Set BURTC compare channel.
*
* @param[in] comp Compare the channel index, must be 0 for current devices.
*
* @param[in] value New compare value.
******************************************************************************/
void BURTC_CompareSet(unsigned int comp, uint32_t value)
{
(void) comp; /* Unused parameter when EFM_ASSERT is undefined. */
EFM_ASSERT(comp == 0U);
#if defined(_BURTC_COMP0_MASK)
/* Modification of COMP0 register requires sync with potential ongoing
* register updates in LF domain. */
regSync(BURTC_SYNCBUSY_COMP0);
/* Configure compare channel 0/. */
BURTC->COMP0 = value;
#else
/* Wait for last potential write to complete. */
regSync(BURTC_SYNCBUSY_COMP);
/* Configure compare channel 0 */
BURTC->COMP = value;
regSync(BURTC_SYNCBUSY_COMP);
#endif
}
/***************************************************************************//**
* @brief Get the BURTC compare value.
*
* @param[in] comp Compare the channel index value, must be 0 for Giant/Leopard Gecko.
*
* @return The currently configured value for this compare channel.
******************************************************************************/
uint32_t BURTC_CompareGet(unsigned int comp)
{
(void) comp; /* Unused parameter when EFM_ASSERT is undefined. */
EFM_ASSERT(comp == 0U);
#if defined(_BURTC_COMP0_MASK)
return BURTC->COMP0;
#else
return BURTC->COMP;
#endif
}
/***************************************************************************//**
* @brief Reset counter
******************************************************************************/
void BURTC_CounterReset(void)
{
#if defined(_BURTC_CTRL_MASK)
/* Set and clear reset bit */
BUS_RegBitWrite(&BURTC->CTRL, _BURTC_CTRL_RSTEN_SHIFT, 1U);
BUS_RegBitWrite(&BURTC->CTRL, _BURTC_CTRL_RSTEN_SHIFT, 0U);
#else
BURTC_Stop();
BURTC->CNT = 0U;
BURTC_Start();
#endif
}
/***************************************************************************//**
* @brief
* Restore BURTC to reset state.
* @note
* Before accessing the BURTC, BURSTEN in RMU->CTRL must be cleared.
* LOCK will not be reset to default value, as this will disable access
* to core BURTC registers.
******************************************************************************/
void BURTC_Reset(void)
{
#if defined(_SILICON_LABS_32B_SERIES_0)
bool buResetState;
/* Read reset state, set reset, and restore state. */
buResetState = BUS_RegBitRead(&RMU->CTRL, _RMU_CTRL_BURSTEN_SHIFT);
BUS_RegBitWrite(&RMU->CTRL, _RMU_CTRL_BURSTEN_SHIFT, 1);
BUS_RegBitWrite(&RMU->CTRL, _RMU_CTRL_BURSTEN_SHIFT, buResetState);
#elif defined(_SILICON_LABS_32B_SERIES_2)
if (BURTC->EN != 0U) {
BURTC_SyncWait();
}
BURTC->EN_SET = BURTC_EN_EN;
BURTC_Stop();
BURTC->CNT = 0x0;
BURTC->PRECNT = 0x0;
BURTC->COMP = 0x0;
BURTC->EM4WUEN = _BURTC_EM4WUEN_RESETVALUE;
BURTC->IEN = _BURTC_IEN_RESETVALUE;
BURTC->IF_CLR = _BURTC_IF_MASK;
/* Wait for all values to synchronize. BusFaults can happen if we don't
* do this before the enable bit is cleared. */
BURTC_SyncWait();
BURTC->EN_CLR = BURTC_EN_EN;
#if defined(_BURTC_SYNCBUSY_EN_MASK)
while (BURTC->SYNCBUSY != 0U) {
// Wait for the EN=0 to synchronize
}
#elif defined(_BURTC_EN_DISABLING_MASK)
while (BURTC->EN & _BURTC_EN_DISABLING_MASK) {
/* Wait for disabling to finish */
}
#endif
BURTC->CFG = _BURTC_CFG_RESETVALUE;
#endif
}
#if defined(_BURTC_CTRL_MASK)
/***************************************************************************//**
* @brief
* Get the clock frequency of the BURTC.
*
* @return
* The current frequency in Hz.
******************************************************************************/
uint32_t BURTC_ClockFreqGet(void)
{
uint32_t clkSel;
uint32_t clkDiv;
uint32_t frequency;
clkSel = BURTC->CTRL & _BURTC_CTRL_CLKSEL_MASK;
clkDiv = (BURTC->CTRL & _BURTC_CTRL_PRESC_MASK) >> _BURTC_CTRL_PRESC_SHIFT;
switch (clkSel) {
/** Ultra-low frequency (1 kHz) clock. */
case BURTC_CTRL_CLKSEL_ULFRCO:
if (_BURTC_CTRL_PRESC_DIV1 == clkDiv) {
frequency = 2000; /* 2 kHz when clock divisor is 1. */
} else {
frequency = SystemULFRCOClockGet(); /* 1 kHz when divisor is different
from 1. */
}
break;
/** Low-frequency RC oscillator. */
case BURTC_CTRL_CLKSEL_LFRCO:
frequency = SystemLFRCOClockGet() / (1 << clkDiv); /* freq=32768/2^clkDiv */
break;
/** Low-frequency crystal oscillator. */
case BURTC_CTRL_CLKSEL_LFXO:
frequency = SystemLFXOClockGet() / (1 << clkDiv); /* freq=32768/2^clkDiv */
break;
default:
/* No clock selected for BURTC. */
frequency = 0;
}
return frequency;
}
#endif
/** @} (end addtogroup burtc) */
#endif /* BURTC_PRESENT */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,518 @@
/***************************************************************************//**
* @file
* @brief Core interrupt handling API
*******************************************************************************
* # License
* <b>Copyright 2018 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* 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_core.h"
#include "sl_assert.h"
/* *INDENT-OFF* */
// *****************************************************************************
/// @addtogroup core CORE - Interrupt Handling
///
///
/// @warning
/// If you are looking for atomic and critical sections, they have been moved
/// to platform/common in the Core API.
///
/// @section core_intro Introduction
///
/// This module provides support for NVIC sections. NVIC sections are like
/// critical sections, except interrupts are masked on an individual IRQ basis.
/// This module also provides an API to relocate the vector table in RAM, and
/// register IRQ handlers in the RAM based interrupt vector table.
///
/// @li <b>NVIC mask section</b>: Mask interrupts (external interrupts) on an
/// individual IRQ basis.
///
/// @section core_examples Examples
///
/// Implement an NVIC critical section:
/// @code{.c}
/// {
/// CORE_DECLARE_NVIC_ZEROMASK(mask); // A zero initialized NVIC disable mask
///
/// // Set mask bits for IRQs to block in the NVIC critical section.
/// // In many cases, you can create the disable mask once upon application
/// // startup and use the mask globally throughout the application lifetime.
/// CORE_NvicMaskSetIRQ(LEUART0_IRQn, &mask);
/// CORE_NvicMaskSetIRQ(VCMP_IRQn, &mask);
///
/// // Enter NVIC critical section with the disable mask
/// CORE_NVIC_SECTION(&mask,
/// ...
/// ... your code goes here ...
/// ...
/// )
/// }
/// @endcode
///
/// @section core_vector_tables Interrupt vector tables
///
/// When using RAM based interrupt vector tables it is the user's responsibility
/// to allocate the table space correctly. The tables must be aligned as specified
/// in the CPU reference manual.
///
/// Use @ref CORE_InitNvicVectorTable() to initialize a RAM based vector table
/// by copying table entries from a source vector table to a target table.
/// VTOR is set to the address of the target vector table.
///
/// Use @ref CORE_GetNvicRamTableHandler() @ref CORE_SetNvicRamTableHandler()
/// to get or set the interrupt handler for a specific IRQn. They both use
/// the interrupt vector table defined by the current VTOR register value.
///
/// @{
// *****************************************************************************
/* *INDENT-ON* */
/*******************************************************************************
************************** GLOBAL FUNCTIONS *******************************
******************************************************************************/
/***************************************************************************//**
* @brief
* Enter a NVIC mask section.
*
* When a NVIC mask section is entered, specified NVIC interrupts
* are disabled.
*
* @deprecated Will be removed from the Simplicity SDK
*
* @param[out] nvicState
* Return NVIC interrupts enable mask prior to section entry.
*
* @param[in] disable
* A mask specifying which NVIC interrupts to disable within the section.
******************************************************************************/
void CORE_EnterNvicMask(CORE_nvicMask_t *nvicState,
const CORE_nvicMask_t *disable)
{
CORE_CRITICAL_SECTION(
*nvicState = *(CORE_nvicMask_t*)((uint32_t)&NVIC->ICER[0]);
*(CORE_nvicMask_t*)((uint32_t)&NVIC->ICER[0]) = *disable;
)
}
/***************************************************************************//**
* @brief
* Disable NVIC interrupts.
*
* @deprecated Will be removed from the Simplicity SDK
*
* @param[in] disable
* A mask specifying which NVIC interrupts to disable.
******************************************************************************/
void CORE_NvicDisableMask(const CORE_nvicMask_t *disable)
{
CORE_CRITICAL_SECTION(
*(CORE_nvicMask_t*)((uint32_t)&NVIC->ICER[0]) = *disable;
)
}
/***************************************************************************//**
* @brief
* Set current NVIC interrupt enable mask.
*
* @deprecated Will be removed from the Simplicity SDK
*
* @param[out] enable
* A mask specifying which NVIC interrupts are currently enabled.
******************************************************************************/
void CORE_NvicEnableMask(const CORE_nvicMask_t *enable)
{
CORE_CRITICAL_SECTION(
*(CORE_nvicMask_t*)((uint32_t)&NVIC->ISER[0]) = *enable;
)
}
/***************************************************************************//**
* @brief
* Brief NVIC interrupt enable/disable sequence to allow handling of
* pending interrupts.
*
* @deprecated Will be removed from the Simplicity SDK
*
* @param[in] enable
* A mask specifying which NVIC interrupts to briefly enable.
*
* @note
* Usually used within an NVIC mask section.
******************************************************************************/
void CORE_YieldNvicMask(const CORE_nvicMask_t *enable)
{
CORE_nvicMask_t nvicMask;
// Get current NVIC enable mask.
CORE_CRITICAL_SECTION(
nvicMask = *(CORE_nvicMask_t*)((uint32_t)&NVIC->ISER[0]);
)
// Make a mask with bits set for those interrupts that are currently
// disabled but are set in the enable mask.
#if (CORE_NVIC_REG_WORDS == 1)
nvicMask.a[0] &= enable->a[0];
nvicMask.a[0] = ~nvicMask.a[0] & enable->a[0];
if (nvicMask.a[0] != 0) {
#elif (CORE_NVIC_REG_WORDS == 2)
nvicMask.a[0] &= enable->a[0];
nvicMask.a[1] &= enable->a[1];
nvicMask.a[0] = ~nvicMask.a[0] & enable->a[0];
nvicMask.a[1] = ~nvicMask.a[1] & enable->a[1];
if ((nvicMask.a[0] != 0U) || (nvicMask.a[1] != 0U)) {
#elif (CORE_NVIC_REG_WORDS == 3)
nvicMask.a[0] &= enable->a[0];
nvicMask.a[1] &= enable->a[1];
nvicMask.a[2] &= enable->a[2];
nvicMask.a[0] = ~nvicMask.a[0] & enable->a[0];
nvicMask.a[1] = ~nvicMask.a[1] & enable->a[1];
nvicMask.a[2] = ~nvicMask.a[2] & enable->a[2];
if ((nvicMask.a[0] != 0U) || (nvicMask.a[1] != 0U) || (nvicMask.a[2] != 0U)) {
#endif
// Enable previously disabled interrupts.
*(CORE_nvicMask_t*)((uint32_t)&NVIC->ISER[0]) = nvicMask;
// Disable those interrupts again.
*(CORE_nvicMask_t*)((uint32_t)&NVIC->ICER[0]) = nvicMask;
}
}
/***************************************************************************//**
* @brief
* Utility function to set an IRQn bit in a NVIC enable/disable mask.
*
* @deprecated Will be removed from the Simplicity SDK
* Use sl_interrupt_manager_enable from the interrupt_manager service to replace
* the calls to this API. Note that each interrupts will need to be enabled
* individually instead of using a mask.
*
* @param[in] irqN
* The IRQn_Type enumerator for the interrupt.
*
* @param[in,out] mask
* The mask to set the interrupt bit in.
******************************************************************************/
void CORE_NvicMaskSetIRQ(IRQn_Type irqN, CORE_nvicMask_t *mask)
{
EFM_ASSERT(((int)irqN >= 0) && ((int)irqN < EXT_IRQ_COUNT));
mask->a[(unsigned)irqN >> 5] |= 1UL << ((unsigned)irqN & 0x1FUL);
}
/***************************************************************************//**
* @brief
* Utility function to clear an IRQn bit in a NVIC enable/disable mask.
*
* @deprecated Will be removed from the Simplicity SDK
* Use sl_interrupt_manager_enable from the interrupt_manager service to replace
* the calls to this API. Note that each interrupts will need to be disabled
* individually instead of using a mask.
*
* @param[in] irqN
* The IRQn_Type enumerator for the interrupt.
*
* @param[in,out] mask
* The mask to clear the interrupt bit in.
******************************************************************************/
void CORE_NvicMaskClearIRQ(IRQn_Type irqN, CORE_nvicMask_t *mask)
{
EFM_ASSERT(((int)irqN >= 0) && ((int)irqN < EXT_IRQ_COUNT));
mask->a[(unsigned)irqN >> 5] &= ~(1UL << ((unsigned)irqN & 0x1FUL));
}
/***************************************************************************//**
* @brief
* Get the current NVIC enable mask state.
*
* @deprecated Will be removed from the Simplicity SDK
*
* @param[out] mask
* The current NVIC enable mask.
******************************************************************************/
void CORE_GetNvicEnabledMask(CORE_nvicMask_t *mask)
{
CORE_CRITICAL_SECTION(
*mask = *(CORE_nvicMask_t*)((uint32_t)&NVIC->ISER[0]);
)
}
/***************************************************************************//**
* @brief
* Get NVIC disable state for a given mask.
*
* @deprecated Will be removed from the Simplicity SDK
*
* @param[in] mask
* An NVIC mask to check.
*
* @return
* True if all NVIC interrupt mask bits are clear.
******************************************************************************/
bool CORE_GetNvicMaskDisableState(const CORE_nvicMask_t *mask)
{
CORE_nvicMask_t nvicMask;
CORE_CRITICAL_SECTION(
nvicMask = *(CORE_nvicMask_t*)((uint32_t)&NVIC->ISER[0]);
)
#if (CORE_NVIC_REG_WORDS == 1)
return (mask->a[0] & nvicMask.a[0]) == 0U;
#elif (CORE_NVIC_REG_WORDS == 2)
return ((mask->a[0] & nvicMask.a[0]) == 0U)
&& ((mask->a[1] & nvicMask.a[1]) == 0U);
#elif (CORE_NVIC_REG_WORDS == 3)
return ((mask->a[0] & nvicMask.a[0]) == 0U)
&& ((mask->a[1] & nvicMask.a[1]) == 0U)
&& ((mask->a[2] & nvicMask.a[2]) == 0U);
#endif
}
/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
/***************************************************************************//**
* @brief Internal function to query the state an IRQ. Present for compatibility
* during the deprecation process.
*
* @param[in] irqN IRQ number.
*
* @return True of False depending on if the IRQ is active in the NVIC or not.
******************************************************************************/
__STATIC_INLINE bool internal_NvicIRQDisabled(IRQn_Type irqN)
{
CORE_nvicMask_t *mask;
EFM_ASSERT(((int)irqN >= 0) && ((int)irqN < EXT_IRQ_COUNT));
mask = (CORE_nvicMask_t*)((uint32_t)&NVIC->ISER[0]);
return (mask->a[(unsigned)irqN >> 5U] & (1UL << ((unsigned)irqN & 0x1FUL)))
== 0UL;
}
/** @endcond */
/***************************************************************************//**
* @brief
* Check if an NVIC interrupt is disabled.
*
* @deprecated Will be removed from the Simplicity SDK, please now use the
* function sl_interrupt_manager_is_irq_disabled in the interrupt manager
* service component.
*
* @param[in] irqN
* The IRQn_Type enumerator for the interrupt to check.
*
* @return
* True if the interrupt is disabled.
******************************************************************************/
bool CORE_NvicIRQDisabled(IRQn_Type irqN)
{
return internal_NvicIRQDisabled(irqN);
}
/***************************************************************************//**
* @brief
* Utility function to get the handler for a specific interrupt.
*
* @deprecated Will be removed from the Simplicity SDK
*
* @param[in] irqN
* The IRQn_Type enumerator for the interrupt.
*
* @return
* The handler address.
*
* @note
* Uses the interrupt vector table defined by the current VTOR register value.
******************************************************************************/
void *CORE_GetNvicRamTableHandler(IRQn_Type irqN)
{
EFM_ASSERT(((int)irqN >= -16) && ((int)irqN < EXT_IRQ_COUNT));
return (void*)((uint32_t*)(((uint32_t*)SCB->VTOR)[(int)irqN + 16]));
}
/***************************************************************************//**
* @brief
* Utility function to set the handler for a specific interrupt.
*
* @deprecated Will be removed from the Simplicity SDK, please now use the
* function sl_interrupt_manager_set_irq_handler in the interrupt manager
* service component.
*
* @param[in] irqN
* The IRQn_Type enumerator for the interrupt.
*
* @param[in] handler
* The handler address.
*
* @note
* Uses the interrupt vector table defined by the current VTOR register value.
******************************************************************************/
void CORE_SetNvicRamTableHandler(IRQn_Type irqN, void *handler)
{
EFM_ASSERT(((int)irqN >= -16) && ((int)irqN < EXT_IRQ_COUNT));
((uint32_t*)SCB->VTOR)[(int)irqN + 16] = (uint32_t)((uint32_t*)handler);
}
/***************************************************************************//**
* @brief
* Initialize an interrupt vector table by copying table entries from a
* source to a target table.
*
* @note This function will set a new VTOR register value.
*
* @param[in] sourceTable
* The address of the source vector table.
*
* @param[in] sourceSize
* A number of entries in the source vector table.
*
* @param[in] targetTable
* The address of the target (new) vector table.
*
* @param[in] targetSize
* A number of entries in the target vector table.
*
* @param[in] defaultHandler
* An address of the interrupt handler used for target entries for which where there
* is no corresponding source entry (i.e., the target table is larger than the source
* table).
*
* @param[in] overwriteActive
* When true, a target table entry is always overwritten with the
* corresponding source entry. If false, a target table entry is only
* overwritten if it is zero. This makes it possible for an application
* to partly initialize a target table before passing it to this function.
*
******************************************************************************/
void CORE_InitNvicVectorTable(uint32_t *sourceTable,
uint32_t sourceSize,
uint32_t *targetTable,
uint32_t targetSize,
void *defaultHandler,
bool overwriteActive)
{
uint32_t i;
// ASSERT on non SRAM-based target table.
EFM_ASSERT(((uint32_t)targetTable >= SRAM_BASE)
&& ((uint32_t)targetTable < (SRAM_BASE + SRAM_SIZE)));
// ASSERT if misaligned with respect to the VTOR register implementation.
#if defined(SCB_VTOR_TBLBASE_Msk)
EFM_ASSERT(((uint32_t)targetTable & ~(SCB_VTOR_TBLOFF_Msk
| SCB_VTOR_TBLBASE_Msk)) == 0U);
#else
EFM_ASSERT(((uint32_t)targetTable & ~SCB_VTOR_TBLOFF_Msk) == 0U);
#endif
// ASSERT if misaligned with respect to the vector table size.
// The vector table address must be aligned at its size rounded up to nearest 2^n.
EFM_ASSERT(((uint32_t)targetTable
& ((1UL << (32UL - __CLZ((targetSize * 4UL) - 1UL))) - 1UL))
== 0UL);
for (i = 0; i < targetSize; i++) {
if (overwriteActive) { // Overwrite target entries.
if (i < sourceSize) { // targetSize <= sourceSize
targetTable[i] = sourceTable[i];
} else { // targetSize > sourceSize
targetTable[i] = (uint32_t)((uint32_t*)defaultHandler);
}
} else { // Overwrite target entries which are 0.
if (i < sourceSize) { // targetSize <= sourceSize
if (targetTable[i] == 0U) {
targetTable[i] = sourceTable[i];
}
} else { // targetSize > sourceSize
if (targetTable[i] == 0U) {
targetTable[i] = (uint32_t)((uint32_t*)defaultHandler);
}
}
}
}
SCB->VTOR = (uint32_t)targetTable;
}
/***************************************************************************//**
* @brief
* Check if a specific interrupt is disabled or blocked.
*
* @deprecated Will be removed from the Simplicity SDK, please now use the
* function sl_interrupt_manager_is_irq_blocked in the interrupt manager
* service component.
*
* @param[in] irqN
* The IRQn_Type enumerator for the interrupt to check.
*
* @return
* True if the interrupt is disabled or blocked.
******************************************************************************/
SL_WEAK bool CORE_IrqIsBlocked(IRQn_Type irqN)
{
uint32_t irqPri, activeIrq;
#if (__CORTEX_M >= 3)
uint32_t basepri;
EFM_ASSERT((irqN >= MemoryManagement_IRQn)
&& (irqN < (IRQn_Type)EXT_IRQ_COUNT));
#else
EFM_ASSERT((irqN >= SVCall_IRQn) && ((IRQn_Type)irqN < EXT_IRQ_COUNT));
#endif
if ((__get_PRIMASK() & 1U) != 0U) {
return true; // All IRQs are disabled.
}
if (internal_NvicIRQDisabled(irqN)) {
return true; // The IRQ in question is disabled.
}
irqPri = NVIC_GetPriority(irqN);
#if (__CORTEX_M >= 3)
basepri = __get_BASEPRI();
if ((basepri != 0U)
&& (irqPri >= (basepri >> (8U - __NVIC_PRIO_BITS)))) {
return true; // The IRQ in question has too low
} // priority vs. BASEPRI.
#endif
// Check if already in an interrupt handler. If so, an interrupt with a
// higher priority (lower priority value) can preempt.
activeIrq = (SCB->ICSR & SCB_ICSR_VECTACTIVE_Msk) >> SCB_ICSR_VECTACTIVE_Pos;
if (activeIrq != 0U) {
if (irqPri >= NVIC_GetPriority((IRQn_Type)(activeIrq - 16U))) {
return true; // The IRQ in question has too low
} // priority vs. current active IRQ
}
return false;
}
/** @} (end addtogroup core) */

View File

@@ -0,0 +1,132 @@
/***************************************************************************//**
* @file
* @brief Debug (DBG) Peripheral API
*******************************************************************************
* # License
* <b>Copyright 2018 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* 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_dbg.h"
#if defined(CoreDebug_DHCSR_C_DEBUGEN_Msk)
#include "sl_assert.h"
#include "em_cmu.h"
#include "em_gpio.h"
#include "em_msc.h"
/***************************************************************************//**
* @addtogroup dbg DBG - Debug
* @brief Debug (DBG) Peripheral API
* @details
* This module contains functions to control the DBG peripheral of Silicon
* Labs 32-bit MCUs and SoCs. The Debug Interface is used to program and debug
* Silicon Labs devices.
* @{
******************************************************************************/
/*******************************************************************************
************************** GLOBAL FUNCTIONS *******************************
******************************************************************************/
#if defined(GPIO_ROUTE_SWOPEN) || defined(GPIO_ROUTEPEN_SWVPEN) \
|| defined(GPIO_TRACEROUTEPEN_SWVPEN)
/***************************************************************************//**
* @brief
* Enable Serial Wire Output (SWO) pin.
*
* @details
* The SWO pin (sometimes denoted SWV, serial wire viewer) allows for
* miscellaneous output to be passed from the Cortex-M3 debug trace module to
* an external debug probe. By default, the debug trace module and pin output
* may be disabled.
*
* Since the SWO pin is only useful when using a debugger, a suggested use
* of this function during startup may be:
* @verbatim
* if (DBG_Connected())
* {
* DBG_SWOEnable(1);
* }
* @endverbatim
* By checking if the debugger is attached, a setup leading to a higher energy
* consumption when the debugger is attached can be avoided when not using
* a debugger.
*
* Another alternative may be to set the debugger tool chain to configure
* the required setup (similar to the content of this function) by some
* sort of toolchain scripting during its attach/reset procedure. In that
* case, the above suggested code for enabling the SWO pin is not required
* in the application.
*
* @param[in] location
* A pin location used for SWO pin on the application in use.
******************************************************************************/
void DBG_SWOEnable(unsigned int location)
{
int port;
int pin;
#if defined(GPIO_SWV_PORT)
port = GPIO_SWV_PORT;
pin = GPIO_SWV_PIN;
#else
EFM_ASSERT(location < AFCHANLOC_MAX);
#if defined (AF_DBG_SWO_PORT)
port = AF_DBG_SWO_PORT(location);
pin = AF_DBG_SWO_PIN(location);
#elif defined (AF_DBG_SWV_PORT)
port = AF_DBG_SWV_PORT(location);
pin = AF_DBG_SWV_PIN(location);
#else
#warning "AF debug port is not defined."
#endif
#endif
/* Port/pin location not defined for the device. */
if ((pin < 0) || (port < 0)) {
EFM_ASSERT(0);
return;
}
/* Ensure that the auxiliary clock going to the Cortex debug trace module is enabled. */
#if !defined(_SILICON_LABS_32B_SERIES_2)
CMU_OscillatorEnable(cmuOsc_AUXHFRCO, true, false);
#endif
/* Set the selected pin location for the SWO pin and enable it. */
GPIO_DbgLocationSet(location);
GPIO_DbgSWOEnable(true);
/* Configure the SWO pin for output. */
GPIO_PinModeSet((GPIO_Port_TypeDef)port, pin, gpioModePushPull, 0);
}
#endif
/** @} (end addtogroup dbg) */
#endif /* defined( CoreDebug_DHCSR_C_DEBUGEN_Msk ) */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,138 @@
/***************************************************************************//**
* @file
* @brief General Purpose Cyclic Redundancy Check (GPCRC) API.
*******************************************************************************
* # License
* <b>Copyright 2018 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* 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 "sl_common.h"
#include "em_gpcrc.h"
#include "sl_assert.h"
#if defined(GPCRC_PRESENT) && (GPCRC_COUNT > 0)
/***************************************************************************//**
* @addtogroup gpcrc
* @{
******************************************************************************/
/*******************************************************************************
*************************** GLOBAL FUNCTIONS ******************************
******************************************************************************/
/***************************************************************************//**
* @brief
* Initialize the General Purpose Cyclic Redundancy Check (GPCRC) module.
*
* @details
* Use this function to configure the operational parameters of the GPCRC,
* such as the polynomial to use and how the input should be preprocessed
* before entering the CRC calculation.
*
* @note
* This function will not copy the initialization value to the data register
* to prepare for a new CRC calculation. Either call
* @ref GPCRC_Start before each calculation or by use the
* autoInit functionality.
*
* @param[in] gpcrc
* A pointer to the GPCRC peripheral register block.
*
* @param[in] init
* A pointer to the initialization structure used to configure the GPCRC.
******************************************************************************/
void GPCRC_Init(GPCRC_TypeDef * gpcrc, const GPCRC_Init_TypeDef * init)
{
uint32_t polySelect;
uint32_t revPoly = 0;
if (init->crcPoly == 0x04C11DB7) {
polySelect = GPCRC_CTRL_POLYSEL_CRC32;
} else {
// If not using the fixed CRC-32 polynomial, use 16-bit.
EFM_ASSERT((init->crcPoly & 0xFFFF0000UL) == 0U);
#if defined(GPCRC_CTRL_POLYSEL_CRC16)
polySelect = GPCRC_CTRL_POLYSEL_CRC16;
#else
polySelect = GPCRC_CTRL_POLYSEL_16;
#endif
revPoly = SL_RBIT16(init->crcPoly);
}
#if defined(GPCRC_EN_EN)
if (init->enable) {
gpcrc->EN_SET = GPCRC_EN_EN;
} else {
gpcrc->EN_CLR = GPCRC_EN_EN;
}
gpcrc->CTRL = (((uint32_t)init->autoInit << _GPCRC_CTRL_AUTOINIT_SHIFT)
| ((uint32_t)init->reverseByteOrder << _GPCRC_CTRL_BYTEREVERSE_SHIFT)
| ((uint32_t)init->reverseBits << _GPCRC_CTRL_BITREVERSE_SHIFT)
| ((uint32_t)init->enableByteMode << _GPCRC_CTRL_BYTEMODE_SHIFT)
| polySelect);
#else
gpcrc->CTRL = (((uint32_t)init->autoInit << _GPCRC_CTRL_AUTOINIT_SHIFT)
| ((uint32_t)init->reverseByteOrder << _GPCRC_CTRL_BYTEREVERSE_SHIFT)
| ((uint32_t)init->reverseBits << _GPCRC_CTRL_BITREVERSE_SHIFT)
| ((uint32_t)init->enableByteMode << _GPCRC_CTRL_BYTEMODE_SHIFT)
| polySelect
| ((uint32_t)init->enable << _GPCRC_CTRL_EN_SHIFT));
#endif
#if defined(GPCRC_CTRL_POLYSEL_CRC16)
if (polySelect == GPCRC_CTRL_POLYSEL_CRC16) {
#else
if (polySelect == GPCRC_CTRL_POLYSEL_16) {
#endif
// Set the CRC polynomial value.
gpcrc->POLY = revPoly & _GPCRC_POLY_POLY_MASK;
}
// Load the CRC initialization value to GPCRC_INIT.
gpcrc->INIT = init->initValue;
}
/***************************************************************************//**
* @brief
* Reset GPCRC registers to the hardware reset state.
*
* @note
* The data registers are not reset by this function.
*
* @param[in] gpcrc
* A pointer to the GPCRC peripheral register block.
******************************************************************************/
void GPCRC_Reset(GPCRC_TypeDef * gpcrc)
{
gpcrc->CTRL = _GPCRC_CTRL_RESETVALUE;
gpcrc->POLY = _GPCRC_POLY_RESETVALUE;
gpcrc->INIT = _GPCRC_INIT_RESETVALUE;
}
/** @} (end addtogroup gpcrc) */
#endif /* defined(GPCRC_COUNT) && (GPCRC_COUNT > 0) */

View File

@@ -0,0 +1,452 @@
/***************************************************************************//**
* @file
* @brief General Purpose IO (GPIO) peripheral API
* devices.
*******************************************************************************
* # License
* <b>Copyright 2018 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* 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_gpio.h"
#if defined(GPIO_COUNT) && (GPIO_COUNT > 0)
/***************************************************************************//**
* @addtogroup gpio GPIO - General Purpose Input/Output
* @brief General Purpose Input/Output (GPIO) API
* @details
* This module contains functions to control the GPIO peripheral of Silicon
* Labs 32-bit MCUs and SoCs. The GPIO peripheral is used for pin configuration
* and direct pin manipulation and sensing as well as routing for peripheral
* pin connections.
* @{
******************************************************************************/
/*******************************************************************************
******************************* DEFINES ***********************************
******************************************************************************/
/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
/** Validation of the pin typically usable in assert statements. */
#define GPIO_DRIVEMODE_VALID(mode) ((mode) <= 3)
#define GPIO_STRENGTH_VALID(strength) (!((strength) \
& ~(_GPIO_P_CTRL_DRIVESTRENGTH_MASK \
| _GPIO_P_CTRL_DRIVESTRENGTHALT_MASK)))
/** @endcond */
/*******************************************************************************
************************** GLOBAL FUNCTIONS *******************************
******************************************************************************/
/***************************************************************************//**
* @brief
* Sets the pin location of the debug pins (Serial Wire interface).
*
* @note
* Changing the pins used for debugging uncontrolled, may result in a lockout.
*
* @param[in] location
* The debug pin location to use (0-3).
******************************************************************************/
void GPIO_DbgLocationSet(unsigned int location)
{
#if defined (_GPIO_ROUTE_SWLOCATION_MASK)
EFM_ASSERT(location < AFCHANLOC_MAX);
GPIO->ROUTE = (GPIO->ROUTE & ~_GPIO_ROUTE_SWLOCATION_MASK)
| (location << _GPIO_ROUTE_SWLOCATION_SHIFT);
#elif defined (_GPIO_ROUTELOC0_SWVLOC_MASK)
EFM_ASSERT(location < AFCHANLOC_MAX);
GPIO->ROUTELOC0 = (GPIO->ROUTELOC0 & ~_GPIO_ROUTELOC0_SWVLOC_MASK)
| (location << _GPIO_ROUTELOC0_SWVLOC_SHIFT);
#else
(void)location;
#endif
}
#if defined (_GPIO_P_CTRL_DRIVEMODE_MASK)
/***************************************************************************//**
* @brief
* Sets drive mode for a GPIO port.
*
* @param[in] port
* The GPIO port to access.
*
* @param[in] mode
* Drive mode to use for the port.
******************************************************************************/
void GPIO_DriveModeSet(GPIO_Port_TypeDef port, GPIO_DriveMode_TypeDef mode)
{
EFM_ASSERT(GPIO_PORT_VALID(port) && GPIO_DRIVEMODE_VALID(mode));
GPIO->P[port].CTRL = (GPIO->P[port].CTRL & ~(_GPIO_P_CTRL_DRIVEMODE_MASK))
| (mode << _GPIO_P_CTRL_DRIVEMODE_SHIFT);
}
#endif
#if defined (_GPIO_P_CTRL_DRIVESTRENGTH_MASK)
/***************************************************************************//**
* @brief
* Sets the drive strength for a GPIO port.
*
* @param[in] port
* The GPIO port to access.
*
* @param[in] strength
* The drive strength to use for the port.
******************************************************************************/
void GPIO_DriveStrengthSet(GPIO_Port_TypeDef port,
GPIO_DriveStrength_TypeDef strength)
{
EFM_ASSERT(GPIO_PORT_VALID(port) && GPIO_STRENGTH_VALID(strength));
BUS_RegMaskedWrite(&GPIO->P[port].CTRL,
_GPIO_P_CTRL_DRIVESTRENGTH_MASK | _GPIO_P_CTRL_DRIVESTRENGTHALT_MASK,
strength);
}
#endif
/***************************************************************************//**
* @brief
* Configure the GPIO external pin interrupt.
*
* @details
* It is recommended to disable interrupts before configuring the GPIO pin interrupt.
* See @ref GPIO_IntDisable() for more information.
*
* The GPIO interrupt handler must be in place before enabling the
* interrupt.
*
* Notice that any pending interrupt for the selected interrupt is cleared
* by this function.
*
* @note
* On series 0 devices, the pin number parameter is not used. The
* pin number used on these devices is hardwired to the interrupt with the
* same number. @n
* On series 1 devices, the pin number can be selected freely within a group.
* Interrupt numbers are divided into 4 groups (intNo / 4) and valid pin
* number within the interrupt groups are:
* 0: pins 0-3 (interrupt number 0-3)
* 1: pins 4-7 (interrupt number 4-7)
* 2: pins 8-11 (interrupt number 8-11)
* 3: pins 12-15 (interrupt number 12-15)
*
* @param[in] port
* The port to associate with the @p pin.
*
* @param[in] pin
* The pin number on the port.
*
* @param[in] intNo
* The interrupt number to trigger.
*
* @param[in] risingEdge
* Set to true if the interrupt will be enabled on the rising edge. Otherwise, false.
*
* @param[in] fallingEdge
* Set to true if the interrupt will be enabled on the falling edge. Otherwise, false.
*
* @param[in] enable
* Set to true if the interrupt will be enabled after the configuration is complete.
* False to leave disabled. See @ref GPIO_IntDisable() and @ref GPIO_IntEnable().
******************************************************************************/
void GPIO_ExtIntConfig(GPIO_Port_TypeDef port,
unsigned int pin,
unsigned int intNo,
bool risingEdge,
bool fallingEdge,
bool enable)
{
#if defined (_GPIO_EXTIPSELH_MASK)
uint32_t tmp = 0;
#endif
#if !defined(_GPIO_EXTIPINSELL_MASK)
(void)pin;
#endif
EFM_ASSERT(GPIO_PORT_PIN_VALID(port, pin));
#if defined(_GPIO_EXTIPINSELL_MASK)
EFM_ASSERT(GPIO_INTNO_PIN_VALID(intNo, pin));
#endif
/* The EXTIPSELL register controls pins 0-7 and EXTIPSELH controls
* pins 8-15 of the interrupt configuration. */
if (intNo < 8) {
BUS_RegMaskedWrite(&GPIO->EXTIPSELL,
_GPIO_EXTIPSELL_EXTIPSEL0_MASK
<< (_GPIO_EXTIPSELL_EXTIPSEL1_SHIFT * intNo),
(uint32_t)port << (_GPIO_EXTIPSELL_EXTIPSEL1_SHIFT * intNo));
} else {
#if defined(_GPIO_EXTIPSELH_MASK)
tmp = intNo - 8;
#if defined(_GPIO_EXTIPSELH_EXTIPSEL0_MASK)
BUS_RegMaskedWrite(&GPIO->EXTIPSELH,
_GPIO_EXTIPSELH_EXTIPSEL0_MASK
<< (_GPIO_EXTIPSELH_EXTIPSEL1_SHIFT * tmp),
(uint32_t)port << (_GPIO_EXTIPSELH_EXTIPSEL1_SHIFT * tmp));
#elif defined(_GPIO_EXTIPSELH_EXTIPSEL8_MASK)
BUS_RegMaskedWrite(&GPIO->EXTIPSELH,
_GPIO_EXTIPSELH_EXTIPSEL8_MASK
<< (_GPIO_EXTIPSELH_EXTIPSEL9_SHIFT * tmp),
(uint32_t)port << (_GPIO_EXTIPSELH_EXTIPSEL9_SHIFT * tmp));
#else
#error Invalid GPIO_EXTIPINSELH bit fields
#endif
#endif /* #if defined(_GPIO_EXTIPSELH_MASK) */
}
#if defined(_GPIO_EXTIPINSELL_MASK)
/* The EXTIPINSELL register controls interrupt 0-7 and EXTIPINSELH controls
* interrupt 8-15 of the interrupt/pin number mapping. */
if (intNo < 8) {
BUS_RegMaskedWrite(&GPIO->EXTIPINSELL,
_GPIO_EXTIPINSELL_EXTIPINSEL0_MASK
<< (_GPIO_EXTIPINSELL_EXTIPINSEL1_SHIFT * intNo),
(uint32_t)((pin % 4) & _GPIO_EXTIPINSELL_EXTIPINSEL0_MASK)
<< (_GPIO_EXTIPINSELL_EXTIPINSEL1_SHIFT * intNo));
} else {
#if defined (_GPIO_EXTIPINSELH_EXTIPINSEL8_MASK)
BUS_RegMaskedWrite(&GPIO->EXTIPINSELH,
_GPIO_EXTIPINSELH_EXTIPINSEL8_MASK
<< (_GPIO_EXTIPINSELH_EXTIPINSEL9_SHIFT * tmp),
(uint32_t)((pin % 4) & _GPIO_EXTIPINSELH_EXTIPINSEL8_MASK)
<< (_GPIO_EXTIPSELH_EXTIPSEL9_SHIFT * tmp));
#endif
#if defined (_GPIO_EXTIPINSELH_EXTIPINSEL0_MASK)
BUS_RegMaskedWrite(&GPIO->EXTIPINSELH,
_GPIO_EXTIPINSELH_EXTIPINSEL0_MASK
<< (_GPIO_EXTIPINSELH_EXTIPINSEL1_SHIFT * tmp),
(uint32_t)((pin % 4) & _GPIO_EXTIPINSELH_EXTIPINSEL0_MASK)
<< (_GPIO_EXTIPSELH_EXTIPSEL1_SHIFT * tmp));
#endif
}
#endif
/* Enable/disable the rising edge interrupt. */
BUS_RegBitWrite(&(GPIO->EXTIRISE), intNo, risingEdge);
/* Enable/disable the falling edge interrupt. */
BUS_RegBitWrite(&(GPIO->EXTIFALL), intNo, fallingEdge);
/* Clear any pending interrupt. */
GPIO_IntClear(1 << intNo);
/* Finally enable/disable interrupt. */
BUS_RegBitWrite(&(GPIO->IEN), intNo, enable);
}
#if _SILICON_LABS_32B_SERIES > 0
/***************************************************************************//**
* @brief
* Configure EM4WU pins as external level-sensitive interrupts.
*
* @details
* It is recommended to disable interrupts before configuring the GPIO pin interrupt.
* See @ref GPIO_IntDisable() for more information.
*
* The GPIO interrupt handler must be in place before enabling the
* interrupt.
*
* Notice that any pending interrupt for the selected interrupt is cleared
* by this function.
*
* @note
* The selected port/pin must be mapped to an existant EM4WU interrupt.
* Each EM4WU signal is connected to a fixed pin.
* Refer to the Alternate Function Table in the device Datasheet for the
* location of each EM4WU signal. For example, on xG22 device, the interrupt
* of EM4WU6 is fixed to pin PC00.
*
* @param[in] port
* The port to associate with the @p pin.
*
* @param[in] pin
* The pin number on the port.
*
* @param[in] intNo
* The EM4WU interrupt number to trigger.
*
* @param[in] polarity
* true = Active high level-sensitive interrupt.
* false = Active low level-sensitive interrupt.
*
* @param[in] enable
* Set to true if the interrupt will be enabled after the configuration is complete.
* False to leave disabled. See @ref GPIO_IntDisable() and @ref GPIO_IntEnable().
******************************************************************************/
void GPIO_EM4WUExtIntConfig(GPIO_Port_TypeDef port,
unsigned int pin,
uint32_t intNo,
bool polarity,
bool enable)
{
EFM_ASSERT(GPIO_PORT_PIN_VALID(port, pin));
// GPIO pin mode set.
GPIO_PinModeSet(port, pin, gpioModeInputPullFilter, (unsigned int)!polarity);
// Enable EM4WU function and set polarity
uint32_t polarityMask = (uint32_t)polarity << (intNo + _GPIO_EM4WUEN_EM4WUEN_SHIFT);
uint32_t pinmask = 1UL << (intNo + _GPIO_EM4WUEN_EM4WUEN_SHIFT);
GPIO_EM4EnablePinWakeup(pinmask, polarityMask);
// Enable EM4WU interrupt
#if defined(_SILICON_LABS_32B_SERIES_1)
BUS_RegBitWrite(&(GPIO->IEN), intNo + _GPIO_IEN_EM4WU_SHIFT, enable);
#elif defined(_SILICON_LABS_32B_SERIES_2_CONFIG_1)
BUS_RegBitWrite(&(GPIO->IEN), intNo + _GPIO_IEN_EM4WUIEN_SHIFT, enable);
#else
BUS_RegBitWrite(&(GPIO->IEN), intNo + _GPIO_IEN_EM4WUIEN0_SHIFT, enable);
#endif
}
#endif
/***************************************************************************//**
* @brief
* Set the mode for a GPIO pin.
*
* @param[in] port
* The GPIO port to access.
*
* @param[in] pin
* The pin number in the port.
*
* @param[in] mode
* The desired pin mode.
*
* @param[in] out
* A value to set for the pin in the DOUT register. The DOUT setting is important for
* some input mode configurations to determine the pull-up/down direction.
******************************************************************************/
void GPIO_PinModeSet(GPIO_Port_TypeDef port,
unsigned int pin,
GPIO_Mode_TypeDef mode,
unsigned int out)
{
EFM_ASSERT(GPIO_PORT_PIN_VALID(port, pin));
/* If disabling a pin, do not modify DOUT to reduce the chance of */
/* a glitch/spike (may not be sufficient precaution in all use cases). */
if (mode != gpioModeDisabled) {
if (out) {
GPIO_PinOutSet(port, pin);
} else {
GPIO_PinOutClear(port, pin);
}
}
/* There are two registers controlling the pins for each port. The MODEL
* register controls pins 0-7 and MODEH controls pins 8-15. */
if (pin < 8) {
// Cast parameter [mode] to 32 bits to fix C99 Undefined Behavior (see SEI CERT C INT34-C)
// Compiler assigned 8 bits for enum. Same thing for other branch.
BUS_RegMaskedWrite(&(GPIO->P[port].MODEL), 0xFu << (pin * 4), (uint32_t)mode << (pin * 4));
} else {
BUS_RegMaskedWrite(&(GPIO->P[port].MODEH), 0xFu << ((pin - 8) * 4), (uint32_t)mode << ((pin - 8) * 4));
}
if (mode == gpioModeDisabled) {
if (out) {
GPIO_PinOutSet(port, pin);
} else {
GPIO_PinOutClear(port, pin);
}
}
}
/***************************************************************************//**
* @brief
* Get the mode for a GPIO pin.
*
* @param[in] port
* The GPIO port to access.
*
* @param[in] pin
* The pin number in the port.
*
* @return
* The pin mode.
******************************************************************************/
GPIO_Mode_TypeDef GPIO_PinModeGet(GPIO_Port_TypeDef port,
unsigned int pin)
{
EFM_ASSERT(GPIO_PORT_PIN_VALID(port, pin));
if (pin < 8) {
return (GPIO_Mode_TypeDef) ((GPIO->P[port].MODEL >> (pin * 4)) & 0xF);
} else {
return (GPIO_Mode_TypeDef) ((GPIO->P[port].MODEH >> ((pin - 8) * 4)) & 0xF);
}
}
#if defined(_GPIO_EM4WUEN_MASK)
/**************************************************************************//**
* @brief
* Enable GPIO pin wake-up from EM4. When the function exits,
* EM4 mode can be safely entered.
*
* @note
* It is assumed that the GPIO pin modes are set correctly.
* Valid modes are @ref gpioModeInput and @ref gpioModeInputPull.
*
* @param[in] pinmask
* A bitmask containing the bitwise logic OR of which GPIO pin(s) to enable.
* See Reference Manuals for a pinmask to the GPIO port/pin mapping.
* @param[in] polaritymask
* A bitmask containing the bitwise logic OR of GPIO pin(s) wake-up polarity.
* See Reference Manuals for pinmask-to-GPIO port/pin mapping.
*****************************************************************************/
void GPIO_EM4EnablePinWakeup(uint32_t pinmask, uint32_t polaritymask)
{
EFM_ASSERT((pinmask & ~_GPIO_EM4WUEN_MASK) == 0);
#if defined(_GPIO_EM4WUPOL_MASK)
EFM_ASSERT((polaritymask & ~_GPIO_EM4WUPOL_MASK) == 0);
GPIO->EM4WUPOL &= ~pinmask; /* Set the wakeup polarity. */
GPIO->EM4WUPOL |= pinmask & polaritymask;
#elif defined(_GPIO_EXTILEVEL_MASK)
EFM_ASSERT((polaritymask & ~_GPIO_EXTILEVEL_MASK) == 0);
GPIO->EXTILEVEL &= ~pinmask;
GPIO->EXTILEVEL |= pinmask & polaritymask;
#endif
GPIO->EM4WUEN |= pinmask; /* Enable wakeup. */
GPIO_EM4SetPinRetention(true); /* Enable the pin retention. */
#if defined(_GPIO_CMD_EM4WUCLR_MASK)
GPIO->CMD = GPIO_CMD_EM4WUCLR; /* Clear the wake-up logic. */
#else
GPIO_IntClear(pinmask);
#endif
}
#endif
/** @} (end addtogroup gpio) */
#endif /* defined(GPIO_COUNT) && (GPIO_COUNT > 0) */

View File

@@ -0,0 +1,940 @@
/***************************************************************************//**
* @file
* @brief Inter-integrated Circuit (I2C) Peripheral API
*******************************************************************************
* # License
* <b>Copyright 2018 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* 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_i2c.h"
#if defined(I2C_COUNT) && (I2C_COUNT > 0)
#include "em_cmu.h"
#include "em_bus.h"
#include "sl_assert.h"
#include <limits.h>
/***************************************************************************//**
* @addtogroup i2c I2C - Inter-Integrated Circuit
* @brief Inter-integrated Circuit (I2C) Peripheral API
* @details
* This module contains functions to control the I2C peripheral of Silicon
* Labs 32-bit MCUs and SoCs. The I2C interface allows communication on I2C
* buses with the lowest energy consumption possible.
* @{
******************************************************************************/
/*******************************************************************************
******************************* DEFINES ***********************************
******************************************************************************/
/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
/** Validation of the I2C register block pointer reference for assert statements. */
#if (I2C_COUNT == 1)
#define I2C_REF_VALID(ref) ((ref) == I2C0)
#elif (I2C_COUNT == 2)
#define I2C_REF_VALID(ref) (((ref) == I2C0) || ((ref) == I2C1))
#elif (I2C_COUNT == 3)
#define I2C_REF_VALID(ref) (((ref) == I2C0) || ((ref) == I2C1) || ((ref) == I2C2))
#elif (I2C_COUNT == 4)
#define I2C_REF_VALID(ref) (((ref) == I2C0) || ((ref) == I2C1) || ((ref) == I2C2) || ((ref) == I2C3))
#endif
/** Error flags indicating that the I2C transfer has failed. */
/* Notice that I2C_IF_TXOF (transmit overflow) is not really possible with */
/* the software-supporting master mode. Likewise, for I2C_IF_RXUF (receive underflow) */
/* RXUF is only likely to occur with the software if using a debugger peeking into */
/* the RXDATA register. Therefore, those types of faults are ignored. */
#define I2C_IF_ERRORS (I2C_IF_BUSERR | I2C_IF_ARBLOST)
#define I2C_IEN_ERRORS (I2C_IEN_BUSERR | I2C_IEN_ARBLOST)
/* Maximum I2C transmission rate constant. */
#if defined(_SILICON_LABS_32B_SERIES_0)
#if defined(_EFM32_HAPPY_FAMILY) || defined(_EFM32_ZERO_FAMILY)
#define I2C_CR_MAX 8
#else
#define I2C_CR_MAX 4
#endif
#elif defined(_SILICON_LABS_32B_SERIES_1)
#define I2C_CR_MAX 8
#elif defined(_SILICON_LABS_32B_SERIES_2)
#define I2C_CR_MAX 8
#else
#warning "Max I2C transmission rate constant is not defined"
#endif
/** @endcond */
/*******************************************************************************
******************************** ENUMS ************************************
******************************************************************************/
/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
/** Master mode transfer states. */
typedef enum {
i2cStateStartAddrSend, /**< Send start + (first part of) address. */
i2cStateAddrWFAckNack, /**< Wait for ACK/NACK on (the first part of) address. */
i2cStateAddrWF2ndAckNack, /**< Wait for ACK/NACK on the second part of a 10 bit address. */
i2cStateRStartAddrSend, /**< Send a repeated start + (first part of) address. */
i2cStateRAddrWFAckNack, /**< Wait for ACK/NACK on an address sent after a repeated start. */
i2cStateDataSend, /**< Send data. */
i2cStateDataWFAckNack, /**< Wait for ACK/NACK on data sent. */
i2cStateWFData, /**< Wait for data. */
i2cStateWFStopSent, /**< Wait for STOP to have been transmitted. */
i2cStateDone /**< Transfer completed successfully. */
} I2C_TransferState_TypeDef;
/** @endcond */
/*******************************************************************************
******************************* STRUCTS ***********************************
******************************************************************************/
/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
/** Structure used to store state information on an ongoing master mode transfer. */
typedef struct {
/** Current state. */
I2C_TransferState_TypeDef state;
/** Result return code. */
I2C_TransferReturn_TypeDef result;
/** Offset in the current sequence buffer. */
uint16_t offset;
/* Index to the current sequence buffer in use. */
uint8_t bufIndx;
/** Reference to the I2C transfer sequence definition provided by the user. */
I2C_TransferSeq_TypeDef *seq;
} I2C_Transfer_TypeDef;
/** @endcond */
/*******************************************************************************
***************************** LOCAL DATA *******^**************************
******************************************************************************/
/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
/**
* Lookup table for Nlow + Nhigh setting defined by CLHR. Set the undefined
* index (0x3) to reflect a default setting just in case.
*/
static const uint8_t i2cNSum[] = { 4 + 4, 6 + 3, 11 + 6, 4 + 4 };
/** A transfer state information for an ongoing master mode transfer. */
static I2C_Transfer_TypeDef i2cTransfer[I2C_COUNT];
/** @endcond */
/*******************************************************************************
************************** LOCAL FUNCTIONS *******************************
******************************************************************************/
/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
/***************************************************************************//**
* @brief
* Empty received data buffer.
******************************************************************************/
static void flushRx(I2C_TypeDef *i2c)
{
while (i2c->STATUS & I2C_STATUS_RXDATAV) {
i2c->RXDATA;
}
#if defined(_SILICON_LABS_32B_SERIES_2)
/* SW needs to clear RXDATAV IF on Series 2 devices.
Flag is kept high by HW if buffer is not empty. */
I2C_IntClear(i2c, I2C_IF_RXDATAV);
#endif
}
/** @endcond */
/*******************************************************************************
************************** GLOBAL FUNCTIONS *******************************
******************************************************************************/
/***************************************************************************//**
* @brief
* Get the current configured I2C bus frequency.
*
* @details
* This frequency is only relevant when acting as master.
*
* @note
* The actual frequency is a real number, this function returns a rounded
* down (truncated) integer value.
*
* @param[in] i2c
* A pointer to the I2C peripheral register block.
*
* @return
* The current I2C frequency in Hz.
******************************************************************************/
uint32_t I2C_BusFreqGet(I2C_TypeDef *i2c)
{
uint32_t freqHfper = 0;
uint32_t n;
/* Maximum frequency is given by freqScl = freqHfper/((Nlow + Nhigh)(DIV + 1) + I2C_CR_MAX)
* For more details, see the reference manual
* I2C Clock Generation chapter. */
if (i2c == I2C0) {
freqHfper = CMU_ClockFreqGet(cmuClock_I2C0);
#if defined(I2C1)
} else if (i2c == I2C1) {
freqHfper = CMU_ClockFreqGet(cmuClock_I2C1);
#endif
#if defined(I2C2)
} else if (i2c == I2C2) {
freqHfper = CMU_ClockFreqGet(cmuClock_I2C2);
#endif
} else {
EFM_ASSERT(false);
}
/* n = Nlow + Nhigh */
n = (uint32_t)i2cNSum[(i2c->CTRL & _I2C_CTRL_CLHR_MASK)
>> _I2C_CTRL_CLHR_SHIFT];
return freqHfper / ((n * (i2c->CLKDIV + 1)) + I2C_CR_MAX);
}
/***************************************************************************//**
* @brief
* Set the I2C bus frequency.
*
* @details
* The bus frequency is only relevant when acting as master. The bus
* frequency should not be set higher than the maximum frequency accepted by the
* slowest device on the bus.
*
* Notice that, due to asymmetric requirements on low and high I2C clock
* cycles in the I2C specification, the maximum frequency allowed
* to comply with the specification may be somewhat lower than expected.
*
* See the reference manual, details on I2C clock generation,
* for maximum allowed theoretical frequencies for different modes.
*
* @param[in] i2c
* A pointer to the I2C peripheral register block.
*
* @param[in] freqRef
* An I2C reference clock frequency in Hz that will be used. If set to 0,
* HFPERCLK / HFPERCCLK clock is used. Setting it to a higher than actual
* configured value has the consequence of reducing the real I2C frequency.
*
* @param[in] freqScl
* A bus frequency to set (bus speed may be lower due to integer
* prescaling). Safe (according to the I2C specification) maximum frequencies for
* standard fast and fast+ modes are available using I2C_FREQ_ defines.
* (Using I2C_FREQ_ defines requires corresponding setting of @p type.)
* The slowest slave device on a bus must always be considered.
*
* @param[in] i2cMode
* A clock low-to-high ratio type to use. If not using i2cClockHLRStandard,
* make sure all devices on the bus support the specified mode. Using a
* non-standard ratio is useful to achieve a higher bus clock in fast and
* fast+ modes.
******************************************************************************/
void I2C_BusFreqSet(I2C_TypeDef *i2c,
uint32_t freqRef,
uint32_t freqScl,
I2C_ClockHLR_TypeDef i2cMode)
{
uint32_t n, minFreq, denominator;
int32_t div;
/* Avoid dividing by 0. */
EFM_ASSERT(freqScl);
if (!freqScl) {
return;
}
/* Ensure mode is valid */
i2cMode &= _I2C_CTRL_CLHR_MASK >> _I2C_CTRL_CLHR_SHIFT;
/* Set the CLHR (clock low-to-high ratio). */
i2c->CTRL &= ~_I2C_CTRL_CLHR_MASK;
BUS_RegMaskedWrite(&i2c->CTRL,
_I2C_CTRL_CLHR_MASK,
i2cMode << _I2C_CTRL_CLHR_SHIFT);
if (freqRef == 0) {
if (i2c == I2C0) {
freqRef = CMU_ClockFreqGet(cmuClock_I2C0);
#if defined(I2C1)
} else if (i2c == I2C1) {
freqRef = CMU_ClockFreqGet(cmuClock_I2C1);
#endif
#if defined(I2C2)
} else if (i2c == I2C2) {
freqRef = CMU_ClockFreqGet(cmuClock_I2C2);
#endif
} else {
EFM_ASSERT(false);
}
}
/* Check the minumum HF peripheral clock. */
minFreq = UINT_MAX;
if (i2c->CTRL & I2C_CTRL_SLAVE) {
switch (i2cMode) {
case i2cClockHLRStandard:
#if defined(_SILICON_LABS_32B_SERIES_0)
minFreq = 4200000; break;
#elif defined(_SILICON_LABS_32B_SERIES_1)
minFreq = 2000000; break;
#elif defined(_SILICON_LABS_32B_SERIES_2)
minFreq = 2000000; break;
#endif
case i2cClockHLRAsymetric:
#if defined(_SILICON_LABS_32B_SERIES_0)
minFreq = 11000000; break;
#elif defined(_SILICON_LABS_32B_SERIES_1)
minFreq = 5000000; break;
#elif defined(_SILICON_LABS_32B_SERIES_2)
minFreq = 5000000; break;
#endif
case i2cClockHLRFast:
#if defined(_SILICON_LABS_32B_SERIES_0)
minFreq = 24400000; break;
#elif defined(_SILICON_LABS_32B_SERIES_1)
minFreq = 14000000; break;
#elif defined(_SILICON_LABS_32B_SERIES_2)
minFreq = 14000000; break;
#endif
default:
/* MISRA requires the default case. */
break;
}
} else {
/* For master mode, platform 1 and 2 share the same
minimum frequencies. */
switch (i2cMode) {
case i2cClockHLRStandard:
minFreq = 2000000; break;
case i2cClockHLRAsymetric:
minFreq = 9000000; break;
case i2cClockHLRFast:
minFreq = 20000000; break;
default:
/* MISRA requires default case */
break;
}
}
/* Frequency most be larger-than. */
EFM_ASSERT(freqRef > minFreq);
/* SCL frequency is given by:
* freqScl = freqRef/((Nlow + Nhigh) * (DIV + 1) + I2C_CR_MAX)
*
* Therefore,
* DIV = ((freqRef - (I2C_CR_MAX * freqScl))/((Nlow + Nhigh) * freqScl)) - 1
*
* For more details, see the reference manual
* I2C Clock Generation chapter. */
/* n = Nlow + Nhigh */
n = (uint32_t)i2cNSum[i2cMode];
denominator = n * freqScl;
/* Explicitly ensure denominator is never zero. */
if (denominator == 0) {
EFM_ASSERT(0);
return;
}
/* Perform integer division so that div is rounded up. */
div = (int32_t)(((freqRef - (I2C_CR_MAX * freqScl) + denominator - 1)
/ denominator) - 1);
EFM_ASSERT(div >= 0);
EFM_ASSERT((uint32_t)div <= _I2C_CLKDIV_DIV_MASK);
/* The clock divisor must be at least 1 in slave mode according to the reference */
/* manual (in which case there is normally no need to set the bus frequency). */
if ((i2c->CTRL & I2C_CTRL_SLAVE) && (div == 0)) {
div = 1;
}
i2c->CLKDIV = (uint32_t)div;
}
/***************************************************************************//**
* @brief
* Enable/disable I2C.
*
* @note
* After enabling the I2C (from being disabled), the I2C is in BUSY state.
*
* @param[in] i2c
* A pointer to the I2C peripheral register block.
*
* @param[in] enable
* True to enable counting, false to disable.
******************************************************************************/
void I2C_Enable(I2C_TypeDef *i2c, bool enable)
{
EFM_ASSERT(I2C_REF_VALID(i2c));
#if defined (_I2C_EN_MASK)
BUS_RegBitWrite(&(i2c->EN), _I2C_EN_EN_SHIFT, enable);
#else
BUS_RegBitWrite(&(i2c->CTRL), _I2C_CTRL_EN_SHIFT, enable);
#endif
}
/***************************************************************************//**
* @brief
* Initialize I2C.
*
* @param[in] i2c
* A pointer to the I2C peripheral register block.
*
* @param[in] init
* A pointer to the I2C initialization structure.
******************************************************************************/
void I2C_Init(I2C_TypeDef *i2c, const I2C_Init_TypeDef *init)
{
EFM_ASSERT(I2C_REF_VALID(i2c));
i2c->IEN = 0;
I2C_IntClear(i2c, _I2C_IF_MASK);
/* Set SLAVE select mode. */
BUS_RegBitWrite(&(i2c->CTRL), _I2C_CTRL_SLAVE_SHIFT, init->master ? 0 : 1);
I2C_BusFreqSet(i2c, init->refFreq, init->freq, init->clhr);
I2C_Enable(i2c, init->enable);
}
/***************************************************************************//**
* @brief
* Reset I2C to the same state that it was in after a hardware reset.
*
* @note
* The ROUTE register is NOT reset by this function to allow for
* centralized setup of this feature.
*
* @param[in] i2c
* A pointer to the I2C peripheral register block.
******************************************************************************/
void I2C_Reset(I2C_TypeDef *i2c)
{
// Cancel ongoing operations and clear TX buffer
i2c->CMD = I2C_CMD_CLEARPC | I2C_CMD_CLEARTX | I2C_CMD_ABORT;
i2c->CTRL = _I2C_CTRL_RESETVALUE;
i2c->CLKDIV = _I2C_CLKDIV_RESETVALUE;
i2c->SADDR = _I2C_SADDR_RESETVALUE;
i2c->SADDRMASK = _I2C_SADDRMASK_RESETVALUE;
i2c->IEN = _I2C_IEN_RESETVALUE;
#if defined (_I2C_EN_EN_MASK)
i2c->EN = _I2C_EN_RESETVALUE;
#endif
// Empty received data buffer
flushRx(i2c);
I2C_IntClear(i2c, _I2C_IF_MASK);
/* Do not reset the route register; setting should be done independently. */
}
// *****************************************************************************
/// @brief
/// Continue an initiated I2C transfer (single master mode only).
///
/// @details
/// This function is used repeatedly after a I2C_TransferInit() to
/// complete a transfer. It may be used in polled mode as the below example
/// shows:
/// @code{.c}
/// I2C_TransferReturn_TypeDef ret;
///
/// // Do a polled transfer
/// ret = I2C_TransferInit(I2C0, seq);
/// while (ret == i2cTransferInProgress)
/// {
/// ret = I2C_Transfer(I2C0);
/// }
/// @endcode
/// It may also be used in interrupt driven mode, where this function is invoked
/// from the interrupt handler. Notice that, if used in interrupt mode, NVIC
/// interrupts must be configured and enabled for the I2C bus used. I2C
/// peripheral specific interrupts are managed by this software.
///
/// @note
/// Only single master mode is supported.
///
/// @param[in] i2c
/// A pointer to the I2C peripheral register block.
///
/// @return
/// Returns status for an ongoing transfer.
/// @li #i2cTransferInProgress - indicates that transfer not finished.
/// @li #i2cTransferDone - transfer completed successfully.
/// @li otherwise some sort of error has occurred.
///
// *****************************************************************************
I2C_TransferReturn_TypeDef I2C_Transfer(I2C_TypeDef *i2c)
{
uint32_t tmp;
uint32_t pending;
I2C_Transfer_TypeDef *transfer;
I2C_TransferSeq_TypeDef *seq;
bool finished = false;
EFM_ASSERT(I2C_REF_VALID(i2c));
/* Support up to 2 I2C buses. */
if (i2c == I2C0) {
transfer = i2cTransfer;
}
#if (I2C_COUNT > 1)
else if (i2c == I2C1) {
transfer = i2cTransfer + 1;
}
#endif
#if (I2C_COUNT > 2)
else if (i2c == I2C2) {
transfer = i2cTransfer + 2;
}
#endif
#if (I2C_COUNT > 3)
else if (i2c == I2C3) {
transfer = i2cTransfer + 3;
}
#endif
else {
return i2cTransferUsageFault;
}
seq = transfer->seq;
while (!finished) {
pending = i2c->IF;
/* If some sort of fault, abort transfer. */
if (pending & I2C_IF_ERRORS) {
if (pending & I2C_IF_ARBLOST) {
/* If an arbitration fault, indicates either a slave device */
/* not responding as expected, or other master which is not */
/* supported by this software. */
transfer->result = i2cTransferArbLost;
} else if (pending & I2C_IF_BUSERR) {
/* A bus error indicates a misplaced start or stop, which should */
/* not occur in master mode controlled by this software. */
transfer->result = i2cTransferBusErr;
}
/* Ifan error occurs, it is difficult to know */
/* an exact cause and how to resolve. It will be up to a wrapper */
/* to determine how to handle a fault/recovery if possible. */
transfer->state = i2cStateDone;
break;
}
switch (transfer->state) {
/***************************************************/
/* Send the first start+address (first byte if 10 bit). */
/***************************************************/
case i2cStateStartAddrSend:
if (seq->flags & I2C_FLAG_10BIT_ADDR) {
tmp = (((uint32_t)(seq->addr) >> 8) & 0x06) | 0xf0;
/* In 10 bit address mode, the address following the first */
/* start always indicates write. */
} else {
tmp = (uint32_t)(seq->addr) & 0xfe;
if (seq->flags & I2C_FLAG_READ) {
/* Indicate read request */
tmp |= 1;
}
}
transfer->state = i2cStateAddrWFAckNack;
i2c->TXDATA = tmp;/* Data not transmitted until the START is sent. */
i2c->CMD = I2C_CMD_START;
finished = true;
break;
/*******************************************************/
/* Wait for ACK/NACK on the address (first byte if 10 bit). */
/*******************************************************/
case i2cStateAddrWFAckNack:
if (pending & I2C_IF_NACK) {
I2C_IntClear(i2c, I2C_IF_NACK);
transfer->result = i2cTransferNack;
transfer->state = i2cStateWFStopSent;
i2c->CMD = I2C_CMD_STOP;
} else if (pending & I2C_IF_ACK) {
I2C_IntClear(i2c, I2C_IF_ACK);
/* If a 10 bit address, send the 2nd byte of the address. */
if (seq->flags & I2C_FLAG_10BIT_ADDR) {
transfer->state = i2cStateAddrWF2ndAckNack;
i2c->TXDATA = (uint32_t)(seq->addr) & 0xff;
} else {
/* Determine whether receiving or sending data. */
if (seq->flags & I2C_FLAG_READ) {
transfer->state = i2cStateWFData;
if (seq->buf[transfer->bufIndx].len == 1) {
i2c->CMD = I2C_CMD_NACK;
}
} else {
transfer->state = i2cStateDataSend;
continue;
}
}
}
finished = true;
break;
/******************************************************/
/* Wait for ACK/NACK on the second byte of a 10 bit address. */
/******************************************************/
case i2cStateAddrWF2ndAckNack:
if (pending & I2C_IF_NACK) {
I2C_IntClear(i2c, I2C_IF_NACK);
transfer->result = i2cTransferNack;
transfer->state = i2cStateWFStopSent;
i2c->CMD = I2C_CMD_STOP;
} else if (pending & I2C_IF_ACK) {
I2C_IntClear(i2c, I2C_IF_ACK);
/* If using a plain read sequence with a 10 bit address, switch to send */
/* a repeated start. */
if (seq->flags & I2C_FLAG_READ) {
transfer->state = i2cStateRStartAddrSend;
}
/* Otherwise, expected to write 0 or more bytes. */
else {
transfer->state = i2cStateDataSend;
}
continue;
}
finished = true;
break;
/*******************************/
/* Send a repeated start+address */
/*******************************/
case i2cStateRStartAddrSend:
if (seq->flags & I2C_FLAG_10BIT_ADDR) {
tmp = (uint32_t)((seq->addr >> 8) & 0x06) | 0xf0;
} else {
tmp = (uint32_t)(seq->addr & 0xfe);
}
/* If this is a write+read combined sequence, read is about to start. */
if (seq->flags & I2C_FLAG_WRITE_READ) {
/* Indicate a read request. */
tmp |= 1;
/* If reading only one byte, prepare the NACK now before START command. */
if (seq->buf[transfer->bufIndx].len == 1) {
i2c->CMD = I2C_CMD_NACK;
}
}
transfer->state = i2cStateRAddrWFAckNack;
/* The START command has to be written first since repeated start. Otherwise, */
/* data would be sent first. */
i2c->CMD = I2C_CMD_START;
i2c->TXDATA = tmp;
finished = true;
break;
/**********************************************************************/
/* Wait for ACK/NACK on the repeated start+address (first byte if 10 bit) */
/**********************************************************************/
case i2cStateRAddrWFAckNack:
if (pending & I2C_IF_NACK) {
I2C_IntClear(i2c, I2C_IF_NACK);
transfer->result = i2cTransferNack;
transfer->state = i2cStateWFStopSent;
i2c->CMD = I2C_CMD_STOP;
} else if (pending & I2C_IF_ACK) {
I2C_IntClear(i2c, I2C_IF_ACK);
/* Determine whether receiving or sending data. */
if (seq->flags & I2C_FLAG_WRITE_READ) {
transfer->state = i2cStateWFData;
} else {
transfer->state = i2cStateDataSend;
continue;
}
}
finished = true;
break;
/*****************************/
/* Send a data byte to the slave */
/*****************************/
case i2cStateDataSend:
/* Reached end of data buffer. */
if (transfer->offset >= seq->buf[transfer->bufIndx].len) {
/* Move to the next message part. */
transfer->offset = 0;
transfer->bufIndx++;
/* Send a repeated start when switching to read mode on the 2nd buffer. */
if (seq->flags & I2C_FLAG_WRITE_READ) {
transfer->state = i2cStateRStartAddrSend;
continue;
}
/* Only writing from one buffer or finished both buffers. */
if ((seq->flags & I2C_FLAG_WRITE) || (transfer->bufIndx > 1)) {
transfer->state = i2cStateWFStopSent;
i2c->CMD = I2C_CMD_STOP;
finished = true;
break;
}
/* Reprocess in case the next buffer is empty. */
continue;
}
/* Send byte. */
i2c->TXDATA = (uint32_t)(seq->buf[transfer->bufIndx].data[transfer->offset++]);
transfer->state = i2cStateDataWFAckNack;
finished = true;
break;
/*********************************************************/
/* Wait for ACK/NACK from the slave after sending data to it. */
/*********************************************************/
case i2cStateDataWFAckNack:
if (pending & I2C_IF_NACK) {
I2C_IntClear(i2c, I2C_IF_NACK);
transfer->result = i2cTransferNack;
transfer->state = i2cStateWFStopSent;
i2c->CMD = I2C_CMD_STOP;
} else if (pending & I2C_IF_ACK) {
I2C_IntClear(i2c, I2C_IF_ACK);
transfer->state = i2cStateDataSend;
continue;
}
finished = true;
break;
/****************************/
/* Wait for data from slave */
/****************************/
case i2cStateWFData:
if (pending & I2C_IF_RXDATAV) {
uint8_t data;
unsigned int rxLen = seq->buf[transfer->bufIndx].len;
/* Must read out data not to block further progress. */
data = (uint8_t)(i2c->RXDATA);
#if (defined(_SILICON_LABS_32B_SERIES_2_CONFIG_1) \
|| defined(_SILICON_LABS_32B_SERIES_2_CONFIG_2) \
|| defined(_SILICON_LABS_32B_SERIES_2_CONFIG_3))
// Errata I2C_E303. I2C Fails to Indicate New Incoming Data.
uint32_t status = i2c->STATUS;
// look for invalid RXDATAV = 0 and RXFULL = 1 condition
if (((status & I2C_IF_RXDATAV) == 0) & ((status & I2C_IF_RXFULL) != 0)) {
// Performing a dummy read of the RXFIFO (I2C_RXDATA).
// This restores the expected RXDATAV = 1 and RXFULL = 0 condition.
(void)i2c->RXDATA;
// The dummy read will also set the RXUFIF flag bit, which should be ignored and cleared.
I2C_IntClear(i2c, I2C_IF_RXUF);
}
#endif
/* SW needs to clear RXDATAV IF on Series 2 devices.
Flag is kept high by HW if buffer is not empty. */
#if defined(_SILICON_LABS_32B_SERIES_2)
I2C_IntClear(i2c, I2C_IF_RXDATAV);
#endif
/* Make sure that there is no storing beyond the end of the buffer (just in case). */
if (transfer->offset < rxLen) {
seq->buf[transfer->bufIndx].data[transfer->offset++] = data;
}
/* If all requested data is read, the sequence should end. */
if (transfer->offset >= rxLen) {
transfer->state = i2cStateWFStopSent;
i2c->CMD = I2C_CMD_STOP;
} else {
/* Send ACK and wait for the next byte. */
i2c->CMD = I2C_CMD_ACK;
if ( (1 < rxLen) && (transfer->offset == (rxLen - 1)) ) {
/* If receiving more than one byte and this is the next
to last byte, transmit the NACK now before receiving
the last byte. */
i2c->CMD = I2C_CMD_NACK;
}
}
}
finished = true;
break;
/***********************************/
/* Wait for STOP to have been sent */
/***********************************/
case i2cStateWFStopSent:
if (pending & I2C_IF_MSTOP) {
I2C_IntClear(i2c, I2C_IF_MSTOP);
transfer->state = i2cStateDone;
}
finished = true;
break;
/******************************/
/* An unexpected state, software fault */
/******************************/
default:
transfer->result = i2cTransferSwFault;
transfer->state = i2cStateDone;
finished = true;
break;
}
}
if (transfer->state == i2cStateDone) {
/* Disable interrupt sources when done. */
i2c->IEN = 0;
/* Update the result unless a fault has already occurred. */
if (transfer->result == i2cTransferInProgress) {
transfer->result = i2cTransferDone;
}
}
/* Until transfer is done, keep returning i2cTransferInProgress. */
else {
return i2cTransferInProgress;
}
return transfer->result;
}
/***************************************************************************//**
* @brief
* Prepare and start an I2C transfer (single master mode only).
*
* @details
* This function must be invoked to start an I2C transfer
* sequence. To complete the transfer, I2C_Transfer() must
* be used either in polled mode or by adding a small driver wrapper using
* interrupts.
*
* @note
* Only single master mode is supported.
*
* @param[in] i2c
* A pointer to the I2C peripheral register block.
*
* @param[in] seq
* A pointer to the sequence structure defining the I2C transfer to take place. The
* referenced structure must exist until the transfer has fully completed.
*
* @return
* Returns the status for an ongoing transfer:
* @li #i2cTransferInProgress - indicates that the transfer is not finished.
* @li Otherwise, an error has occurred.
******************************************************************************/
I2C_TransferReturn_TypeDef I2C_TransferInit(I2C_TypeDef *i2c,
I2C_TransferSeq_TypeDef *seq)
{
I2C_Transfer_TypeDef *transfer;
EFM_ASSERT(I2C_REF_VALID(i2c));
EFM_ASSERT(seq);
/* Support up to 2 I2C buses. */
if (i2c == I2C0) {
transfer = i2cTransfer;
}
#if (I2C_COUNT > 1)
else if (i2c == I2C1) {
transfer = i2cTransfer + 1;
}
#endif
#if (I2C_COUNT > 2)
else if (i2c == I2C2) {
transfer = i2cTransfer + 2;
}
#endif
#if (I2C_COUNT > 3)
else if (i2c == I2C3) {
transfer = i2cTransfer + 3;
}
#endif
else {
return i2cTransferUsageFault;
}
/* Check if in a busy state. Since this software assumes a single master, */
/* issue an abort. The BUSY state is normal after a reset. */
if (i2c->STATE & I2C_STATE_BUSY) {
i2c->CMD = I2C_CMD_ABORT;
}
/* Do not try to read 0 bytes. It is not */
/* possible according to the I2C spec, since the slave will always start */
/* sending the first byte ACK on an address. The read operation can */
/* only be stopped by NACKing a received byte, i.e., minimum 1 byte. */
if (((seq->flags & I2C_FLAG_READ) && !(seq->buf[0].len))
|| ((seq->flags & I2C_FLAG_WRITE_READ) && !(seq->buf[1].len))
) {
return i2cTransferUsageFault;
}
/* Prepare for a transfer. */
transfer->state = i2cStateStartAddrSend;
transfer->result = i2cTransferInProgress;
transfer->offset = 0;
transfer->bufIndx = 0;
transfer->seq = seq;
/* Ensure buffers are empty. */
i2c->CMD = I2C_CMD_CLEARPC | I2C_CMD_CLEARTX;
flushRx(i2c);
/* Clear all pending interrupts prior to starting a transfer. */
I2C_IntClear(i2c, _I2C_IF_MASK);
/* Enable relevant interrupts. */
/* Notice that the I2C interrupt must also be enabled in the NVIC, but */
/* that is left for an additional driver wrapper. */
i2c->IEN |= I2C_IEN_NACK | I2C_IEN_ACK | I2C_IEN_MSTOP
| I2C_IEN_RXDATAV | I2C_IEN_ERRORS;
/* Start a transfer. */
return I2C_Transfer(i2c);
}
/** @} (end addtogroup i2c) */
#endif /* defined(I2C_COUNT) && (I2C_COUNT > 0) */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,461 @@
/***************************************************************************//**
* @file
* @brief Direct memory access (LDMA) module peripheral API
*******************************************************************************
* # License
* <b>Copyright 2018 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* 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_ldma.h"
#if defined(LDMA_PRESENT) && (LDMA_COUNT == 1)
#include <stddef.h>
#include "sl_assert.h"
#include "em_bus.h"
#include "em_cmu.h"
#include "em_core.h"
/***************************************************************************//**
* @addtogroup ldma
* @{
******************************************************************************/
#if defined(LDMA_IRQ_HANDLER_TEMPLATE)
/***************************************************************************//**
* @brief
* A template for an LDMA IRQ handler.
******************************************************************************/
void LDMA_IRQHandler(void)
{
uint32_t ch;
/* Get all pending and enabled interrupts. */
uint32_t pending = LDMA_IntGetEnabled();
/* Loop on an LDMA error to enable debugging. */
while (pending & LDMA_IF_ERROR) {
}
/* Iterate over all LDMA channels. */
for (ch = 0; ch < DMA_CHAN_COUNT; ch++) {
uint32_t mask = 0x1 << ch;
if (pending & mask) {
/* Clear the interrupt flag. */
LDMA->IFC = mask;
/* Perform more actions here, execute callbacks, and so on. */
}
}
}
#endif
/***************************************************************************//**
* @brief
* De-initialize the LDMA controller.
*
* LDMA interrupts are disabled and the LDMA clock is stopped.
******************************************************************************/
void LDMA_DeInit(void)
{
NVIC_DisableIRQ(LDMA_IRQn);
LDMA->IEN = 0;
#if defined(_LDMA_CHDIS_MASK)
LDMA->CHDIS = _LDMA_CHEN_MASK;
#else
LDMA->CHEN = 0;
#endif
#if defined(LDMA_EN_EN)
LDMA->EN = 0;
#if defined(LDMA_EN_DISABLING)
while (LDMA->EN & _LDMA_EN_DISABLING_MASK) {
}
#endif
#endif
CMU_ClockEnable(cmuClock_LDMA, false);
#if defined(_SILICON_LABS_32B_SERIES_2_CONFIG) && (_SILICON_LABS_32B_SERIES_2_CONFIG > 1)
CMU_ClockEnable(cmuClock_LDMAXBAR, false);
#endif
}
/***************************************************************************//**
* @brief
* Enable or disable an LDMA channel request.
*
* @details
* Use this function to enable or disable an LDMA channel request. This will
* prevent the LDMA from proceeding after its current transaction if disabled.
*
* @param[in] ch
* LDMA channel to enable or disable requests.
*
* @param[in] enable
* If 'true', the request will be enabled. If 'false', the request will be disabled.
******************************************************************************/
void LDMA_EnableChannelRequest(int ch, bool enable)
{
EFM_ASSERT(ch < (int)DMA_CHAN_COUNT);
BUS_RegBitWrite(&LDMA->REQDIS, ch, !enable);
}
/***************************************************************************//**
* @brief
* Initialize the LDMA controller.
*
* @details
* This function will disable all the LDMA channels and enable the LDMA bus
* clock in the CMU. This function will also enable the LDMA IRQ in the NVIC
* and set the LDMA IRQ priority to a user-configurable priority. The LDMA
* interrupt priority is configured using the @ref LDMA_Init_t structure.
*
* @note
* Since this function enables the LDMA IRQ, always add a custom
* LDMA_IRQHandler to the application to handle any interrupts
* from LDMA.
*
* @param[in] init
* A pointer to the initialization structure used to configure the LDMA.
******************************************************************************/
void LDMA_Init(const LDMA_Init_t *init)
{
uint32_t ldmaCtrlVal;
EFM_ASSERT(init != NULL);
EFM_ASSERT(!(((uint32_t)init->ldmaInitCtrlNumFixed << _LDMA_CTRL_NUMFIXED_SHIFT)
& ~_LDMA_CTRL_NUMFIXED_MASK));
EFM_ASSERT(init->ldmaInitIrqPriority < (1 << __NVIC_PRIO_BITS));
CMU_ClockEnable(cmuClock_LDMA, true);
#if defined(_SILICON_LABS_32B_SERIES_2_CONFIG) && (_SILICON_LABS_32B_SERIES_2_CONFIG > 1)
CMU_ClockEnable(cmuClock_LDMAXBAR, true);
#endif
#if defined(LDMA_EN_EN)
LDMA->EN = LDMA_EN_EN;
#endif
ldmaCtrlVal = (uint32_t)init->ldmaInitCtrlNumFixed << _LDMA_CTRL_NUMFIXED_SHIFT;
#if defined(_LDMA_CTRL_SYNCPRSCLREN_SHIFT) && defined (_LDMA_CTRL_SYNCPRSSETEN_SHIFT)
ldmaCtrlVal |= (init->ldmaInitCtrlSyncPrsClrEn << _LDMA_CTRL_SYNCPRSCLREN_SHIFT)
| (init->ldmaInitCtrlSyncPrsSetEn << _LDMA_CTRL_SYNCPRSSETEN_SHIFT);
#endif
LDMA->CTRL = ldmaCtrlVal;
#if defined(_LDMA_SYNCHWEN_SYNCCLREN_SHIFT) && defined (_LDMA_SYNCHWEN_SYNCSETEN_SHIFT)
LDMA->SYNCHWEN = ((uint32_t)init->ldmaInitCtrlSyncPrsClrEn << _LDMA_SYNCHWEN_SYNCCLREN_SHIFT)
| ((uint32_t)init->ldmaInitCtrlSyncPrsSetEn << _LDMA_SYNCHWEN_SYNCSETEN_SHIFT);
#endif
#if defined(_LDMA_CHDIS_MASK)
LDMA->CHDIS = _LDMA_CHEN_MASK;
#else
LDMA->CHEN = 0;
#endif
LDMA->DBGHALT = 0;
LDMA->REQDIS = 0;
/* Enable the LDMA error interrupt. */
LDMA->IEN = LDMA_IEN_ERROR;
#if defined (LDMA_HAS_SET_CLEAR)
LDMA->IF_CLR = 0xFFFFFFFFU;
#else
LDMA->IFC = 0xFFFFFFFFU;
#endif
NVIC_ClearPendingIRQ(LDMA_IRQn);
/* Range is 0-7, where 0 is the highest priority. */
NVIC_SetPriority(LDMA_IRQn, init->ldmaInitIrqPriority);
NVIC_EnableIRQ(LDMA_IRQn);
}
/***************************************************************************//**
* @brief
* Start a DMA transfer.
*
* @param[in] ch
* A DMA channel.
*
* @param[in] transfer
* The initialization structure used to configure the transfer.
*
* @param[in] descriptor
* The transfer descriptor, which can be an array of descriptors linked together.
* Each descriptor's fields stored in RAM will be loaded into the certain
* hardware registers at the proper time to perform the DMA transfer.
******************************************************************************/
void LDMA_StartTransfer(int ch,
const LDMA_TransferCfg_t *transfer,
const LDMA_Descriptor_t *descriptor)
{
#if !(defined (_LDMA_SYNCHWEN_SYNCCLREN_SHIFT) && defined (_LDMA_SYNCHWEN_SYNCSETEN_SHIFT))
uint32_t tmp;
#endif
CORE_DECLARE_IRQ_STATE;
uint32_t chMask = 1UL << (uint8_t)ch;
EFM_ASSERT(ch < (int)DMA_CHAN_COUNT);
EFM_ASSERT(transfer != NULL);
#if defined (_LDMAXBAR_CH_REQSEL_MASK)
EFM_ASSERT(!(transfer->ldmaReqSel & ~_LDMAXBAR_CH_REQSEL_MASK));
#elif defined (_LDMA_CH_REQSEL_MASK)
EFM_ASSERT(!(transfer->ldmaReqSel & ~_LDMA_CH_REQSEL_MASK));
#endif
EFM_ASSERT(!(((uint32_t)transfer->ldmaCfgArbSlots << _LDMA_CH_CFG_ARBSLOTS_SHIFT)
& ~_LDMA_CH_CFG_ARBSLOTS_MASK));
EFM_ASSERT(!(((uint32_t)transfer->ldmaCfgSrcIncSign << _LDMA_CH_CFG_SRCINCSIGN_SHIFT)
& ~_LDMA_CH_CFG_SRCINCSIGN_MASK));
EFM_ASSERT(!(((uint32_t)transfer->ldmaCfgDstIncSign << _LDMA_CH_CFG_DSTINCSIGN_SHIFT)
& ~_LDMA_CH_CFG_DSTINCSIGN_MASK));
/* Clear the pending channel interrupt. */
#if defined (LDMA_HAS_SET_CLEAR)
LDMA->IF_CLR = chMask;
#else
LDMA->IFC = chMask;
#endif
#if defined(LDMAXBAR)
LDMAXBAR->CH[ch].REQSEL = transfer->ldmaReqSel;
#else
LDMA->CH[ch].REQSEL = transfer->ldmaReqSel;
#endif
LDMA->CH[ch].LOOP = transfer->ldmaLoopCnt << _LDMA_CH_LOOP_LOOPCNT_SHIFT;
LDMA->CH[ch].CFG = (transfer->ldmaCfgArbSlots << _LDMA_CH_CFG_ARBSLOTS_SHIFT)
| (transfer->ldmaCfgSrcIncSign << _LDMA_CH_CFG_SRCINCSIGN_SHIFT)
| (transfer->ldmaCfgDstIncSign << _LDMA_CH_CFG_DSTINCSIGN_SHIFT)
#if defined(_LDMA_CH_CFG_SRCBUSPORT_MASK)
| (transfer->ldmaCfgStructBusPort << _LDMA_CH_CFG_STRUCTBUSPORT_SHIFT)
| (transfer->ldmaCfgSrcBusPort << _LDMA_CH_CFG_SRCBUSPORT_SHIFT)
| (transfer->ldmaCfgDstBusPort << _LDMA_CH_CFG_DSTBUSPORT_SHIFT)
#endif
;
/* Set the descriptor address. */
LDMA->CH[ch].LINK = (uint32_t)descriptor & _LDMA_CH_LINK_LINKADDR_MASK;
/* A critical region. */
CORE_ENTER_ATOMIC();
/* Enable the channel interrupt. */
BUS_RegMaskedSet(&LDMA->IEN, chMask);
if (transfer->ldmaReqDis) {
LDMA->REQDIS |= chMask;
}
if (transfer->ldmaDbgHalt) {
LDMA->DBGHALT |= chMask;
}
#if defined (_LDMA_SYNCHWEN_SYNCCLREN_SHIFT) && defined (_LDMA_SYNCHWEN_SYNCSETEN_SHIFT)
LDMA->SYNCHWEN_CLR =
(((uint32_t)transfer->ldmaCtrlSyncPrsClrOff << _LDMA_SYNCHWEN_SYNCCLREN_SHIFT)
| ((uint32_t)transfer->ldmaCtrlSyncPrsSetOff << _LDMA_SYNCHWEN_SYNCSETEN_SHIFT))
& _LDMA_SYNCHWEN_MASK;
LDMA->SYNCHWEN_SET =
(((uint32_t)transfer->ldmaCtrlSyncPrsClrOn << _LDMA_SYNCHWEN_SYNCCLREN_SHIFT)
| ((uint32_t)transfer->ldmaCtrlSyncPrsSetOn << _LDMA_SYNCHWEN_SYNCSETEN_SHIFT))
& _LDMA_SYNCHWEN_MASK;
#elif defined (_LDMA_CTRL_SYNCPRSCLREN_SHIFT) && defined (_LDMA_CTRL_SYNCPRSSETEN_SHIFT)
tmp = LDMA->CTRL;
if (transfer->ldmaCtrlSyncPrsClrOff) {
tmp &= ~_LDMA_CTRL_SYNCPRSCLREN_MASK
| (~transfer->ldmaCtrlSyncPrsClrOff << _LDMA_CTRL_SYNCPRSCLREN_SHIFT);
}
if (transfer->ldmaCtrlSyncPrsClrOn) {
tmp |= transfer->ldmaCtrlSyncPrsClrOn << _LDMA_CTRL_SYNCPRSCLREN_SHIFT;
}
if (transfer->ldmaCtrlSyncPrsSetOff) {
tmp &= ~_LDMA_CTRL_SYNCPRSSETEN_MASK
| (~transfer->ldmaCtrlSyncPrsSetOff << _LDMA_CTRL_SYNCPRSSETEN_SHIFT);
}
if (transfer->ldmaCtrlSyncPrsSetOn) {
tmp |= transfer->ldmaCtrlSyncPrsSetOn << _LDMA_CTRL_SYNCPRSSETEN_SHIFT;
}
LDMA->CTRL = tmp;
#else
#error "SYNC Set and SYNC Clear not defined"
#endif
BUS_RegMaskedClear(&LDMA->CHDONE, chMask); /* Clear the done flag. */
LDMA->LINKLOAD = chMask; /* Start a transfer by loading the descriptor. */
/* A critical region end. */
CORE_EXIT_ATOMIC();
}
#if defined(_LDMA_CH_CTRL_EXTEND_MASK)
/***************************************************************************//**
* @brief
* Start an extended DMA transfer.
*
* @param[in] ch
* A DMA channel.
*
* @param[in] transfer
* The initialization structure used to configure the transfer.
*
* @param[in] descriptor_ext
* The extended transfer descriptor, which can be an array of descriptors
* linked together. Each descriptor's fields stored in RAM will be loaded
* into the certain hardware registers at the proper time to perform the DMA
* transfer.
******************************************************************************/
void LDMA_StartTransferExtend(int ch,
const LDMA_TransferCfg_t *transfer,
const LDMA_DescriptorExtend_t *descriptor_ext)
{
// Ensure destination interleaving supported for given channel.
EFM_ASSERT(((1 << ch) & LDMA_ILCHNL));
LDMA_StartTransfer(ch,
transfer,
(const LDMA_Descriptor_t *)descriptor_ext);
}
#endif
/***************************************************************************//**
* @brief
* Stop a DMA transfer.
*
* @note
* The DMA will complete the current AHB burst transfer before stopping.
*
* @param[in] ch
* A DMA channel to stop.
******************************************************************************/
void LDMA_StopTransfer(int ch)
{
uint32_t chMask = 1UL << (uint8_t)ch;
EFM_ASSERT(ch < (int)DMA_CHAN_COUNT);
#if defined(_LDMA_CHDIS_MASK)
CORE_ATOMIC_SECTION(
LDMA->IEN &= ~chMask;
LDMA->CHDIS = chMask;
)
#else
CORE_ATOMIC_SECTION(
LDMA->IEN &= ~chMask;
BUS_RegMaskedClear(&LDMA->CHEN, chMask);
)
#endif
}
/***************************************************************************//**
* @brief
* Check if a DMA transfer has completed.
*
* @param[in] ch
* A DMA channel to check.
*
* @return
* True if transfer has completed, false if not.
******************************************************************************/
bool LDMA_TransferDone(int ch)
{
bool retVal = false;
uint32_t chMask = 1UL << (uint8_t)ch;
EFM_ASSERT(ch < (int)DMA_CHAN_COUNT);
#if defined(_LDMA_CHSTATUS_MASK)
CORE_ATOMIC_SECTION(
if (((LDMA->CHSTATUS & chMask) == 0) && ((LDMA->CHDONE & chMask) == chMask)) {
retVal = true;
}
)
#else
CORE_ATOMIC_SECTION(
if (((LDMA->CHEN & chMask) == 0) && ((LDMA->CHDONE & chMask) == chMask)) {
retVal = true;
}
)
#endif
return retVal;
}
/***************************************************************************//**
* @brief
* Get the number of items remaining in a transfer.
*
* @note
* This function does not take into account that a DMA transfer with
* a chain of linked transfers might be ongoing. It will only check the
* count for the current transfer.
*
* @param[in] ch
* The channel number of the transfer to check.
*
* @return
* A number of items remaining in the transfer.
******************************************************************************/
uint32_t LDMA_TransferRemainingCount(int ch)
{
uint32_t remaining, done;
uint32_t chMask = 1UL << (uint8_t)ch;
EFM_ASSERT(ch < (int)DMA_CHAN_COUNT);
CORE_ATOMIC_SECTION(
done = LDMA->CHDONE;
remaining = LDMA->CH[ch].CTRL;
)
done &= chMask;
if (done) {
return 0;
}
remaining = (remaining & _LDMA_CH_CTRL_XFERCNT_MASK)
>> _LDMA_CH_CTRL_XFERCNT_SHIFT;
/* +1 because XFERCNT is 0-based. */
return remaining + 1;
}
/** @} (end addtogroup ldma) */
#endif /* defined( LDMA_PRESENT ) && ( LDMA_COUNT == 1 ) */

View File

@@ -0,0 +1,685 @@
/***************************************************************************//**
* @file
* @brief Low Energy Timer (LETIMER) Peripheral API
*******************************************************************************
* # License
* <b>Copyright 2018 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* 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_letimer.h"
#if defined(LETIMER_COUNT) && (LETIMER_COUNT > 0)
#include "em_cmu.h"
#include "sl_assert.h"
/***************************************************************************//**
* @addtogroup letimer LETIMER - Low Energy Timer
* @brief Low Energy Timer (LETIMER) Peripheral API
* @details
* This module contains functions to control the LETIMER peripheral of Silicon
* Labs 32-bit MCUs and SoCs. The LETIMER is a down-counter that can keep track
* of time and output configurable waveforms.
* @{
******************************************************************************/
/*******************************************************************************
******************************* DEFINES ***********************************
******************************************************************************/
/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
/** A validation of the valid comparator register for assert statements. */
#define LETIMER_COMP_REG_VALID(reg) (((reg) <= 1))
/** A validation of the LETIMER register block pointer reference for assert statements. */
#if (LETIMER_COUNT == 1)
#define LETIMER_REF_VALID(ref) ((ref) == LETIMER0)
#elif (LETIMER_COUNT == 2)
#define LETIMER_REF_VALID(ref) (((ref) == LETIMER0) || ((ref) == LETIMER1))
#else
#error Undefined number of analog comparators (ACMP).
#endif
/** A validation of the valid repeat counter register for assert statements. */
#define LETIMER_REP_REG_VALID(reg) (((reg) <= 1))
/** @endcond */
/*******************************************************************************
************************** LOCAL FUNCTIONS ********************************
******************************************************************************/
/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
/***************************************************************************//**
* @brief
* Wait for an ongoing sync of register(s) to the low-frequency domain to complete.
*
* @note
* See the reference manual chapter about Access to Low Energy Peripherals
* (Asynchronos Registers) for details.
*
* @param[in] letimer
* A pointer to the LETIMER peripheral register block.
*
* @param[in] mask
* A bitmask corresponding to SYNCBUSY register defined bits, indicating
* registers that must complete any ongoing synchronization.
******************************************************************************/
__STATIC_INLINE void regSync(LETIMER_TypeDef *letimer, uint32_t mask)
{
#if defined(_LETIMER_FREEZE_MASK)
/* Avoid a deadlock if modifying the same register twice when freeze mode is */
/* activated. */
if (letimer->FREEZE & LETIMER_FREEZE_REGFREEZE) {
return;
}
#endif
/* Wait for any pending write operation to complete. */
while (letimer->SYNCBUSY & mask) {
}
}
/** @endcond */
/*******************************************************************************
************************** GLOBAL FUNCTIONS *******************************
******************************************************************************/
/***************************************************************************//**
* @brief
* Get the LETIMER compare register value.
*
* @param[in] letimer
* A pointer to the LETIMER peripheral register block.
*
* @param[in] comp
* A compare register to get, either 0 or 1.
*
* @return
* A compare register value, 0 if invalid register selected.
******************************************************************************/
uint32_t LETIMER_CompareGet(LETIMER_TypeDef *letimer, unsigned int comp)
{
uint32_t ret;
EFM_ASSERT(LETIMER_REF_VALID(letimer) && LETIMER_COMP_REG_VALID(comp));
/* Initialize the selected compare value. */
switch (comp) {
case 0:
#if defined(LETIMER_SYNCBUSY_COMP0)
regSync(letimer, LETIMER_SYNCBUSY_COMP0);
#endif
ret = letimer->COMP0;
break;
case 1:
#if defined(LETIMER_SYNCBUSY_COMP1)
regSync(letimer, LETIMER_SYNCBUSY_COMP1);
#endif
ret = letimer->COMP1;
break;
default:
/* An unknown compare register selected. */
ret = 0;
break;
}
return ret;
}
/***************************************************************************//**
* @brief
* Get LETIMER counter value.
*
* @param[in] letimer
* Pointer to the LETIMER peripheral register block.
*
* @return
* Current LETIMER counter value.
******************************************************************************/
uint32_t LETIMER_CounterGet(LETIMER_TypeDef *letimer)
{
#if defined(LETIMER_SYNCBUSY_CNT)
regSync(letimer, LETIMER_SYNCBUSY_CNT);
#endif
return letimer->CNT;
}
#if !defined(_EFM32_GECKO_FAMILY)
/***************************************************************************//**
* @brief
* Set LETIMER counter value.
*
* @param[in] letimer
* Pointer to the LETIMER peripheral register block.
*
* @param[in] value
* New counter value.
******************************************************************************/
void LETIMER_CounterSet(LETIMER_TypeDef *letimer, uint32_t value)
{
#if defined(LETIMER_SYNCBUSY_CNT)
regSync(letimer, LETIMER_SYNCBUSY_CNT);
#endif
letimer->CNT = value;
}
#endif
/***************************************************************************//**
* @brief
* Set the LETIMER compare register value.
*
* @note
* The setting of a compare register requires synchronization into the
* low frequency domain. If the same register is modified before a previous
* update has completed, this function will stall until the previous
* synchronization has completed. This only applies to the Gecko Family. See
* comments in the LETIMER_Sync() internal function call.
*
* @param[in] letimer
* A pointer to the LETIMER peripheral register block.
*
* @param[in] comp
* A compare register to set, either 0 or 1.
*
* @param[in] value
* An initialization value (<= 0x0000ffff).
******************************************************************************/
void LETIMER_CompareSet(LETIMER_TypeDef *letimer,
unsigned int comp,
uint32_t value)
{
EFM_ASSERT(LETIMER_REF_VALID(letimer)
&& LETIMER_COMP_REG_VALID(comp)
&& ((value & ~(_LETIMER_COMP0_COMP0_MASK
>> _LETIMER_COMP0_COMP0_SHIFT))
== 0));
/* Initialize the selected compare value. */
switch (comp) {
case 0:
#if defined(LETIMER_SYNCBUSY_COMP0)
regSync(letimer, LETIMER_SYNCBUSY_COMP0);
#endif
letimer->COMP0 = value;
break;
case 1:
#if defined(LETIMER_SYNCBUSY_COMP1)
regSync(letimer, LETIMER_SYNCBUSY_COMP1);
#endif
letimer->COMP1 = value;
break;
default:
/* An unknown compare register selected, abort. */
break;
}
}
/***************************************************************************//**
* @brief
* Start/stop LETIMER.
*
* @note
* The enabling/disabling of the LETIMER modifies the LETIMER CMD register
* which requires synchronization into the low-frequency domain. If this
* register is modified before a previous update to the same register has
* completed, this function will stall until the previous synchronization has
* completed. This only applies to the Gecko Family. See comments in the
* LETIMER_Sync() internal function call.
*
* @param[in] letimer
* A pointer to the LETIMER peripheral register block.
*
* @param[in] enable
* True to enable counting, false to disable.
******************************************************************************/
void LETIMER_Enable(LETIMER_TypeDef *letimer, bool enable)
{
EFM_ASSERT(LETIMER_REF_VALID(letimer));
#if defined(LETIMER_SYNCBUSY_CMD)
regSync(letimer, LETIMER_SYNCBUSY_CMD);
#elif defined (LETIMER_SYNCBUSY_START) && defined (LETIMER_SYNCBUSY_STOP)
regSync(letimer, LETIMER_SYNCBUSY_STOP | LETIMER_SYNCBUSY_START);
#endif
if (enable) {
letimer->CMD = LETIMER_CMD_START;
} else {
letimer->CMD = LETIMER_CMD_STOP;
}
}
#if defined(_LETIMER_FREEZE_MASK)
/***************************************************************************//**
* @brief
* LETIMER register synchronization freeze control.
*
* @details
* Some LETIMER registers require synchronization into the low-frequency (LF)
* domain. The freeze feature allows for several such registers to be
* modified before passing them to the LF domain simultaneously (which
* takes place when the freeze mode is disabled).
*
* @note
* When enabling freeze mode, this function will wait for all current
* ongoing LETIMER synchronization to the LF domain to complete (Normally
* synchronization will not be in progress.) However, for this reason, when
* using freeze mode, modifications of registers requiring the LF synchronization
* should be done within one freeze enable/disable block to avoid unecessary
* stalling.
*
* @param[in] letimer
* A pointer to the LETIMER peripheral register block.
*
* @param[in] enable
* @li True - enable freeze, modified registers are not propagated to the
* LF domain
* @li False - disables freeze, modified registers are propagated to the LF
* domain
******************************************************************************/
void LETIMER_FreezeEnable(LETIMER_TypeDef *letimer, bool enable)
{
if (enable) {
/*
* Wait for any ongoing LF synchronization to complete to
* protect against the rare case when a user
* - modifies a register requiring LF sync
* - then enables freeze before LF sync completed
* - then modifies the same register again
* since modifying a register while it is in sync progress should be
* avoided.
*/
while (letimer->SYNCBUSY) {
}
letimer->FREEZE = LETIMER_FREEZE_REGFREEZE;
} else {
letimer->FREEZE = 0;
}
}
#endif /* defined(_LETIMER_FREEZE_MASK) */
/***************************************************************************//**
* @brief
* Initialize LETIMER.
*
* @details
* Note that the compare/repeat values must be set separately with
* LETIMER_CompareSet() and LETIMER_RepeatSet(). That should probably be done
* prior using this function if configuring the LETIMER to start when
* initialization is complete.
*
* @note
* The initialization of the LETIMER modifies the LETIMER CTRL/CMD registers
* which require synchronization into the low-frequency domain. If any of those
* registers are modified before a previous update to the same register has
* completed, this function will stall until the previous synchronization has
* completed. This only applies to the Gecko Family. See comments in the
* LETIMER_Sync() internal function call.
*
* @param[in] letimer
* A pointer to the LETIMER peripheral register block.
*
* @param[in] init
* A pointer to the LETIMER initialization structure.
******************************************************************************/
void LETIMER_Init(LETIMER_TypeDef *letimer, const LETIMER_Init_TypeDef *init)
{
uint32_t tmp = 0;
EFM_ASSERT(LETIMER_REF_VALID(letimer));
#if defined (LETIMER_EN_EN)
letimer->EN_SET = LETIMER_EN_EN;
#endif
/* Stop the timer if specified to be disabled and running. */
if (!(init->enable) && (letimer->STATUS & LETIMER_STATUS_RUNNING)) {
#if defined(LETIMER_SYNCBUSY_CMD)
regSync(letimer, LETIMER_SYNCBUSY_CMD);
#elif defined(LETIMER_SYNCBUSY_STOP)
regSync(letimer, LETIMER_SYNCBUSY_STOP);
#endif
letimer->CMD = LETIMER_CMD_STOP;
}
/* Configure the DEBUGRUN flag, which sets whether or not the counter should be
* updated when the debugger is active. */
if (init->debugRun) {
tmp |= LETIMER_CTRL_DEBUGRUN;
}
#if defined(LETIMER_CTRL_RTCC0TEN)
if (init->rtcComp0Enable) {
tmp |= LETIMER_CTRL_RTCC0TEN;
}
if (init->rtcComp1Enable) {
tmp |= LETIMER_CTRL_RTCC1TEN;
}
#endif
if ((init->comp0Top) || (init->topValue != 0U)) {
#if defined (LETIMER_CTRL_COMP0TOP)
tmp |= LETIMER_CTRL_COMP0TOP;
if (init->topValue != 0U) {
letimer->COMP0 = init->topValue;
}
#elif defined (LETIMER_CTRL_CNTTOPEN)
tmp |= LETIMER_CTRL_CNTTOPEN;
if (init->topValue != 0U) {
letimer->TOP = init->topValue;
}
#endif
}
if (init->bufTop) {
tmp |= LETIMER_CTRL_BUFTOP;
}
if (init->out0Pol) {
tmp |= LETIMER_CTRL_OPOL0;
}
if (init->out1Pol) {
tmp |= LETIMER_CTRL_OPOL1;
}
tmp |= init->ufoa0 << _LETIMER_CTRL_UFOA0_SHIFT;
tmp |= init->ufoa1 << _LETIMER_CTRL_UFOA1_SHIFT;
tmp |= init->repMode << _LETIMER_CTRL_REPMODE_SHIFT;
#if defined(LETIMER_SYNCBUSY_CTRL)
/* LF register about to be modified requires sync; busy check. */
regSync(letimer, LETIMER_SYNCBUSY_CTRL);
#endif
letimer->CTRL = tmp;
/* Start the timer if specified to be enabled and not already running. */
if (init->enable && !(letimer->STATUS & LETIMER_STATUS_RUNNING)) {
#if defined(LETIMER_SYNCBUSY_CMD)
regSync(letimer, LETIMER_SYNCBUSY_CMD);
#elif defined(LETIMER_SYNCBUSY_START)
regSync(letimer, LETIMER_SYNCBUSY_START);
#endif
letimer->CMD = LETIMER_CMD_START;
}
}
/***************************************************************************//**
* @brief
* Get the LETIMER repeat register value.
*
* @param[in] letimer
* A pointer to the LETIMER peripheral register block.
*
* @param[in] rep
* Repeat register to get, either 0 or 1.
*
* @return
* Repeat register value, 0 if invalid register selected.
******************************************************************************/
uint32_t LETIMER_RepeatGet(LETIMER_TypeDef *letimer, unsigned int rep)
{
uint32_t ret;
EFM_ASSERT(LETIMER_REF_VALID(letimer) && LETIMER_REP_REG_VALID(rep));
/* Initialize the selected compare value. */
switch (rep) {
case 0:
#if defined(LETIMER_SYNCBUSY_REP0)
/* Wait for sync to complete to read the potentially pending value. */
regSync(letimer, LETIMER_SYNCBUSY_REP0);
#endif
ret = letimer->REP0;
break;
case 1:
#if defined(LETIMER_SYNCBUSY_REP1)
regSync(letimer, LETIMER_SYNCBUSY_REP1);
#endif
ret = letimer->REP1;
break;
default:
/* An unknown compare register selected. */
ret = 0;
break;
}
return ret;
}
/***************************************************************************//**
* @brief
* Set the LETIMER repeat counter register value.
*
* @note
* The setting of a repeat counter register requires synchronization into the
* low-frequency domain. If the same register is modified before a previous
* update has completed, this function will stall until the previous
* synchronization has completed. This only applies to the Gecko Family. See
* comments in the LETIMER_Sync() internal function call.
*
* @param[in] letimer
* A pointer to the LETIMER peripheral register block.
*
* @param[in] rep
* Repeat counter register to set, either 0 or 1.
*
* @param[in] value
* An initialization value (<= 0x0000ffff).
******************************************************************************/
void LETIMER_RepeatSet(LETIMER_TypeDef *letimer,
unsigned int rep,
uint32_t value)
{
EFM_ASSERT(LETIMER_REF_VALID(letimer)
&& LETIMER_REP_REG_VALID(rep)
&& ((value & ~(_LETIMER_REP0_REP0_MASK
>> _LETIMER_REP0_REP0_SHIFT))
== 0));
/* Initialize the selected compare value. */
switch (rep) {
case 0:
#if defined(LETIMER_SYNCBUSY_REP0)
regSync(letimer, LETIMER_SYNCBUSY_REP0);
#endif
letimer->REP0 = value;
break;
case 1:
#if defined(LETIMER_SYNCBUSY_REP1)
regSync(letimer, LETIMER_SYNCBUSY_REP1);
#endif
letimer->REP1 = value;
break;
default:
/* An unknown compare register selected, abort. */
break;
}
}
/***************************************************************************//**
* @brief
* Reset LETIMER to the same state that it was in after a hardware reset.
*
* @note
* The ROUTE register is NOT reset by this function to allow for
* a centralized setup of this feature.
*
* @param[in] letimer
* A pointer to the LETIMER peripheral register block.
******************************************************************************/
void LETIMER_Reset(LETIMER_TypeDef *letimer)
{
#if defined(LETIMER_EN_EN)
letimer->EN_SET = LETIMER_EN_EN;
#endif
LETIMER_SyncWait(letimer);
#if defined(LETIMER_SWRST_SWRST)
letimer->SWRST_SET = LETIMER_SWRST_SWRST;
while (letimer->SWRST & _LETIMER_SWRST_RESETTING_MASK) {
}
#else
#if defined(_LETIMER_FREEZE_MASK)
/* Freeze registers to avoid stalling for LF synchronization. */
LETIMER_FreezeEnable(letimer, true);
#endif
/* Make sure disabled first, before resetting other registers. */
letimer->CMD = LETIMER_CMD_STOP | LETIMER_CMD_CLEAR
| LETIMER_CMD_CTO0 | LETIMER_CMD_CTO1;
letimer->CTRL = _LETIMER_CTRL_RESETVALUE;
letimer->COMP0 = _LETIMER_COMP0_RESETVALUE;
letimer->COMP1 = _LETIMER_COMP1_RESETVALUE;
letimer->REP0 = _LETIMER_REP0_RESETVALUE;
letimer->REP1 = _LETIMER_REP1_RESETVALUE;
letimer->IEN = _LETIMER_IEN_RESETVALUE;
LETIMER_IntClear(letimer, _LETIMER_IF_MASK);
#if defined(_LETIMER_FREEZE_MASK)
/* Unfreeze registers and pass new settings to LETIMER. */
LETIMER_FreezeEnable(letimer, false);
#endif
LETIMER_SyncWait(letimer);
#if defined (LETIMER_EN_EN)
letimer->EN_CLR = LETIMER_EN_EN;
#if defined(_LETIMER_EN_DISABLING_MASK)
/*
* Currently, there are no chips without SWRST and with LETIMER_EN_DISABLING
* so this code should never be reached, but that way the same pattern of
* checking the disabling bit is spread across emlib, and code is slightly
* more resilient to feature addition/removal.
*/
while (letimer->EN & _LETIMER_EN_DISABLING_MASK) {
}
#endif
#endif
#endif
}
/***************************************************************************//**
* @brief
* Wait for the LETIMER to complete all synchronization of register changes
* and commands.
*
* @param[in] letimer
* A pointer to the LETIMER peripheral register block.
******************************************************************************/
void LETIMER_SyncWait(LETIMER_TypeDef *letimer)
{
#if defined(_SILICON_LABS_32B_SERIES_2)
while ((letimer->EN != 0U) && (letimer->SYNCBUSY != 0U)) {
/* Wait for previous synchronization to finish */
}
#else
while (letimer->SYNCBUSY != 0U) {
/* Wait for previous synchronization to finish */
}
#endif
}
/***************************************************************************//**
* @brief
* Set the LETIMER top value.
*
* @note
* The LETIMER is a down-counter, so when the counter reaches 0 then the top
* value will be loaded into the counter. This function can be used to set
* the top value.
*
* If the LETIMER is not already configured to use a top value then this
* function will enable that functionality for the user.
*
* @param[in] letimer
* A pointer to the LETIMER peripheral register block.
*
* @param[in] value
* The top value. This can be a 16 bit value on series-0 and series-1 devices
* and a 24 bit value on series-2 devices.
******************************************************************************/
void LETIMER_TopSet(LETIMER_TypeDef *letimer, uint32_t value)
{
#if defined(LETIMER_SYNCBUSY_CTRL)
regSync(letimer, LETIMER_SYNCBUSY_CTRL);
#elif defined(LETIMER_SYNCBUSY_TOP)
regSync(letimer, LETIMER_SYNCBUSY_TOP);
#endif
#if defined(_LETIMER_TOP_MASK)
/* Make sure TOP value is enabled. */
if ((letimer->CTRL & LETIMER_CTRL_CNTTOPEN) == 0U) {
letimer->CTRL_SET = LETIMER_CTRL_CNTTOPEN;
}
letimer->TOP = value;
#else
/* Make sure TOP value is enabled. */
if ((letimer->CTRL & LETIMER_CTRL_COMP0TOP) == 0U) {
letimer->CTRL |= LETIMER_CTRL_COMP0TOP;
}
LETIMER_CompareSet(letimer, 0, value);
#endif
}
/***************************************************************************//**
* @brief
* Get the current LETIMER top value.
*
* @param[in] letimer
* A pointer to the LETIMER peripheral register block.
*
* @return
* The top value. This will be a 16 bit value on series-0 and series-1
* devices and a 24 bit value on series-2 devices.
******************************************************************************/
uint32_t LETIMER_TopGet(LETIMER_TypeDef *letimer)
{
#if defined(_LETIMER_TOP_MASK)
regSync(letimer, LETIMER_SYNCBUSY_TOP);
return letimer->TOP;
#else
#if defined(LETIMER_SYNCBUSY_COMP0)
regSync(letimer, LETIMER_SYNCBUSY_COMP0);
#endif
return letimer->COMP0;
#endif
}
/** @} (end addtogroup letimer) */
#endif /* defined(LETIMER_COUNT) && (LETIMER_COUNT > 0) */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,700 @@
/***************************************************************************//**
* @file
* @brief Operational Amplifier (OPAMP) peripheral API
*******************************************************************************
* # License
* <b>Copyright 2018 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* 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_opamp.h"
#if ((defined(_SILICON_LABS_32B_SERIES_0) && defined(OPAMP_PRESENT) && (OPAMP_COUNT == 1)) \
|| (defined(_SILICON_LABS_32B_SERIES_1) && defined(VDAC_PRESENT) && (VDAC_COUNT > 0)))
#include "em_system.h"
#include "sl_assert.h"
/* *INDENT-OFF* */
/***************************************************************************//**
* @addtogroup opamp OPAMP - Operational Amplifier
* @brief Operational Amplifier (OPAMP) peripheral API
* @details
* This module contains functions to:
* @li OPAMP_Enable() Configure and enable OPAMP.
* @li OPAMP_Disable() Disable OPAMP.
*
* @if DOXYDOC_P1_DEVICE
* All OPAMP functions assume that the DAC clock is running. If DAC is not
* used, the clock can be turned off when OPAMPs are configured.
* @elseif DOXYDOC_P2_DEVICE
* All OPAMP functions assume that the VDAC clock is running. If VDAC is not
* used, the clock can be turned off when the OPAMPs are configured.
* @endif
*
* If the available gain values don't suit the application at hand, the resistor
* ladders can be disabled and external gain programming resistors used.
*
* A number of predefined OPAMP setup macros are available for configuration
* of the most common OPAMP topologies (see figures below).
*
* @note
* <em>The terms POSPAD and NEGPAD in the figures are used to indicate that these
* pads should be connected to a suitable signal ground.</em>
*
* \n<b>Unity gain voltage follower.</b>\n
* @if DOXYDOC_P1_DEVICE
* Use predefined macros @ref OPA_INIT_UNITY_GAIN and
* @ref OPA_INIT_UNITY_GAIN_OPA2.
* @elseif DOXYDOC_P2_DEVICE
* Use predefined macro @ref OPA_INIT_UNITY_GAIN.
* @endif
* @verbatim
|\
___________|+\
| \_______
___|_ / |
| | / |
| |/ |
|___________|
@endverbatim
*
* \n<b>Non-inverting amplifier.</b>\n
* @if DOXYDOC_P1_DEVICE
* Use predefined macros @ref OPA_INIT_NON_INVERTING and
* @ref OPA_INIT_NON_INVERTING_OPA2.
* @elseif DOXYDOC_P2_DEVICE
* Use predefined macro @ref OPA_INIT_NON_INVERTING.
* @endif
* @verbatim
|\
___________|+\
| \_______
___|_ / |
| | / |
| |/ |
|_____R2____|
|
R1
|
NEGPAD @endverbatim
*
* \n<b>Inverting amplifier.</b>\n
* @if DOXYDOC_P1_DEVICE
* Use predefined macros @ref OPA_INIT_INVERTING and
* @ref OPA_INIT_INVERTING_OPA2.
* @elseif DOXYDOC_P2_DEVICE
* Use predefined macro @ref OPA_INIT_INVERTING.
* @endif
* @verbatim
_____R2____
| |
| |\ |
____R1_|___|_\ |
| \____|___
___| /
| |+/
| |/
|
POSPAD @endverbatim
*
* \n<b>Cascaded non-inverting amplifiers.</b>\n
* Use predefined macros @ref OPA_INIT_CASCADED_NON_INVERTING_OPA0,
* @ref OPA_INIT_CASCADED_NON_INVERTING_OPA1 and
* @ref OPA_INIT_CASCADED_NON_INVERTING_OPA2.
* @verbatim
|\ |\ |\
___________|+\ OPA0 ___________|+\ OPA1 ___________|+\ OPA2
| \_________| | \_________| | \_______
___|_ / | ___|_ / | ___|_ / |
| | / | | | / | | | / |
| |/ | | |/ | | |/ |
|_____R2____| |_____R2____| |_____R2____|
| | |
R1 R1 R1
| | |
NEGPAD NEGPAD NEGPAD @endverbatim
*
* \n<b>Cascaded inverting amplifiers.</b>\n
* Use predefined macros @ref OPA_INIT_CASCADED_INVERTING_OPA0,
* @ref OPA_INIT_CASCADED_INVERTING_OPA1 and
* @ref OPA_INIT_CASCADED_INVERTING_OPA2.
* @verbatim
_____R2____ _____R2____ _____R2____
| | | | | |
| |\ | | |\ | | |\ |
____R1_|___|_\ | ____R1_|___|_\ | ____R1_|___|_\ |
| \____|____| | \____|___| | \____|__
___| / ___| / ___| /
| |+/ OPA0 | |+/ OPA1 | |+/ OPA2
| |/ | |/ | |/
| | |
POSPAD POSPAD POSPAD @endverbatim
*
* \n<b>Differential driver with two opamp's.</b>\n
* Use predefined macros @ref OPA_INIT_DIFF_DRIVER_OPA0 and
* @ref OPA_INIT_DIFF_DRIVER_OPA1.
* @verbatim
__________________________
| +
| _____R2____
|\ | | |
___________|+\ OPA0 | | |\ OPA1 |
| \_________|____R1_|___|_\ | _
___|_ / | | \____|______
| | / | ___| /
| |/ | | |+/
|________________| | |/
|
POSPAD @endverbatim
*
* \n<b>Differential receiver with three opamp's.</b>\n
* Use predefined macros @ref OPA_INIT_DIFF_RECEIVER_OPA0,
* @ref OPA_INIT_DIFF_RECEIVER_OPA1 and @ref OPA_INIT_DIFF_RECEIVER_OPA2.
* @verbatim
|\
__________|+\ OPA1
_ | \_________
___|_ / | | _____R2____
| | / | | | |
| |/ | | | |\ |
|___________| |____R1_|___|_\ |
| \____|___
|\ ____R1_ ___| /
+__________|+\ OPA0 | | |+/ OPA2
| \_________| | |/
___|_ / | R2
| | / | |
| |/ | NEGPAD OPA0
|___________|
@endverbatim
*
* @if DOXYDOC_P2_DEVICE
* \n<b>Instrumentation amplifier.</b>\n
* Use predefined macros @ref OPA_INIT_INSTR_AMP_OPA0 and
* @ref OPA_INIT_INSTR_AMP_OPA1.
* @verbatim
|\
__________|+\ OPA1
| \______________
___|_ / |
| | / |
| |/ R2
|____________|
|
R1
|
R1
____________|
| |
| R2
| |\ |
|___|+\ OPA0 |
| \_____|________
__________|_ /
| /
|/
@endverbatim
* @endif
*
* @{
******************************************************************************/
/* *INDENT-ON* */
/*******************************************************************************
************************** GLOBAL FUNCTIONS *******************************
******************************************************************************/
/***************************************************************************//**
* @brief
* Disable an Operational Amplifier.
*
* @if DOXYDOC_P1_DEVICE
* @param[in] dac
* A pointer to the DAC peripheral register block.
* @elseif DOXYDOC_P2_DEVICE
* @param[in] dac
* A pointer to the VDAC peripheral register block.
* @endif
*
* @param[in] opa
* Selects an OPA, valid values are OPA0, OPA1, and OPA2.
******************************************************************************/
void OPAMP_Disable(
#if defined(_SILICON_LABS_32B_SERIES_0)
DAC_TypeDef *dac,
#elif defined(_SILICON_LABS_32B_SERIES_1)
VDAC_TypeDef *dac,
#endif
OPAMP_TypeDef opa)
{
#if defined(_SILICON_LABS_32B_SERIES_0)
EFM_ASSERT(DAC_REF_VALID(dac));
EFM_ASSERT(DAC_OPA_VALID(opa));
if (opa == OPA0) {
dac->CH0CTRL &= ~DAC_CH0CTRL_EN;
dac->OPACTRL &= ~DAC_OPACTRL_OPA0EN;
} else if (opa == OPA1) {
dac->CH1CTRL &= ~DAC_CH1CTRL_EN;
dac->OPACTRL &= ~DAC_OPACTRL_OPA1EN;
} else { /* OPA2 */
dac->OPACTRL &= ~DAC_OPACTRL_OPA2EN;
}
#elif defined(_SILICON_LABS_32B_SERIES_1)
EFM_ASSERT(VDAC_REF_VALID(dac));
EFM_ASSERT(VDAC_OPA_VALID(opa));
if (opa == OPA0) {
#if defined(VDAC_STATUS_OPA0ENS)
dac->CMD |= VDAC_CMD_OPA0DIS;
while (dac->STATUS & VDAC_STATUS_OPA0ENS) {
}
#endif
#if defined(VDAC_STATUS_OPA1ENS)
} else if (opa == OPA1) {
dac->CMD |= VDAC_CMD_OPA1DIS;
while (dac->STATUS & VDAC_STATUS_OPA1ENS) {
}
#endif
#if defined(VDAC_STATUS_OPA2ENS)
} else if (opa == OPA2) {
dac->CMD |= VDAC_CMD_OPA2DIS;
while (dac->STATUS & VDAC_STATUS_OPA2ENS) {
}
#endif
} else { /* OPA3 */
#if defined(VDAC_STATUS_OPA3ENS)
dac->CMD |= VDAC_CMD_OPA3DIS;
while (dac->STATUS & VDAC_STATUS_OPA3ENS) {
}
#endif
}
#endif
}
/***************************************************************************//**
* @brief
* Configure and enable an Operational Amplifier.
*
* @if DOXYDOC_P1_DEVICE
* @note
* The value of the alternate output enable bit mask in the OPAMP_Init_TypeDef
* structure should consist of one or more of the
* DAC_OPA[opa#]MUX_OUTPEN_OUT[output#] flags
* (defined in \<part_name\>_dac.h) OR'ed together. @n @n
* For OPA0:
* @li DAC_OPA0MUX_OUTPEN_OUT0
* @li DAC_OPA0MUX_OUTPEN_OUT1
* @li DAC_OPA0MUX_OUTPEN_OUT2
* @li DAC_OPA0MUX_OUTPEN_OUT3
* @li DAC_OPA0MUX_OUTPEN_OUT4
*
* For OPA1:
* @li DAC_OPA1MUX_OUTPEN_OUT0
* @li DAC_OPA1MUX_OUTPEN_OUT1
* @li DAC_OPA1MUX_OUTPEN_OUT2
* @li DAC_OPA1MUX_OUTPEN_OUT3
* @li DAC_OPA1MUX_OUTPEN_OUT4
*
* For OPA2:
* @li DAC_OPA2MUX_OUTPEN_OUT0
* @li DAC_OPA2MUX_OUTPEN_OUT1
*
* E.g: @n
* init.outPen = DAC_OPA0MUX_OUTPEN_OUT0 | DAC_OPA0MUX_OUTPEN_OUT4;
*
* @param[in] dac
* A pointer to the DAC peripheral register block.
* @elseif DOXYDOC_P2_DEVICE
* @note
* The value of the alternate output enable bit mask in the OPAMP_Init_TypeDef
* structure should consist of one or more of the
* VDAC_OPA_OUT_ALTOUTPADEN_OUT[output#] flags
* (defined in \<part_name\>_vdac.h) OR'ed together. @n @n
* @li VDAC_OPA_OUT_ALTOUTPADEN_OUT0
* @li VDAC_OPA_OUT_ALTOUTPADEN_OUT1
* @li VDAC_OPA_OUT_ALTOUTPADEN_OUT2
* @li VDAC_OPA_OUT_ALTOUTPADEN_OUT3
* @li VDAC_OPA_OUT_ALTOUTPADEN_OUT4
*
* For example: @n
* init.outPen = VDAC_OPA_OUT_ALTOUTPADEN_OUT0 | VDAC_OPA_OUT_ALTOUTPADEN_OUT4;
* @param[in] dac
* A pointer to the VDAC peripheral register block.
* @endif
*
* @param[in] opa
* Selects an OPA, valid values are OPA0, OPA1, and OPA2.
*
* @param[in] init
* A pointer to a structure containing OPAMP initialization information.
******************************************************************************/
void OPAMP_Enable(
#if defined(_SILICON_LABS_32B_SERIES_0)
DAC_TypeDef *dac,
#elif defined(_SILICON_LABS_32B_SERIES_1)
VDAC_TypeDef *dac,
#endif
OPAMP_TypeDef opa,
const OPAMP_Init_TypeDef *init)
{
#if defined(_SILICON_LABS_32B_SERIES_0)
uint32_t gain;
EFM_ASSERT(DAC_REF_VALID(dac));
EFM_ASSERT(DAC_OPA_VALID(opa));
EFM_ASSERT(init->bias <= (_DAC_BIASPROG_BIASPROG_MASK
>> _DAC_BIASPROG_BIASPROG_SHIFT));
if (opa == OPA0) {
EFM_ASSERT((init->outPen & ~_DAC_OPA0MUX_OUTPEN_MASK) == 0);
dac->BIASPROG = (dac->BIASPROG
& ~(_DAC_BIASPROG_BIASPROG_MASK
| DAC_BIASPROG_HALFBIAS))
| (init->bias << _DAC_BIASPROG_BIASPROG_SHIFT)
| (init->halfBias ? DAC_BIASPROG_HALFBIAS : 0);
if (init->defaultOffset) {
gain = dac->CAL & _DAC_CAL_GAIN_MASK;
SYSTEM_GetCalibrationValue(&dac->CAL);
dac->CAL = (dac->CAL & ~_DAC_CAL_GAIN_MASK) | gain;
} else {
EFM_ASSERT(init->offset <= (_DAC_CAL_CH0OFFSET_MASK
>> _DAC_CAL_CH0OFFSET_SHIFT));
dac->CAL = (dac->CAL & ~_DAC_CAL_CH0OFFSET_MASK)
| (init->offset << _DAC_CAL_CH0OFFSET_SHIFT);
}
dac->OPA0MUX = (uint32_t)init->resSel
| (uint32_t)init->outMode
| init->outPen
| (uint32_t)init->resInMux
| (uint32_t)init->negSel
| (uint32_t)init->posSel
| (init->nextOut ? DAC_OPA0MUX_NEXTOUT : 0)
| (init->npEn ? DAC_OPA0MUX_NPEN : 0)
| (init->ppEn ? DAC_OPA0MUX_PPEN : 0);
dac->CH0CTRL |= DAC_CH0CTRL_EN;
dac->OPACTRL = (dac->OPACTRL
& ~(DAC_OPACTRL_OPA0SHORT
| _DAC_OPACTRL_OPA0LPFDIS_MASK
| DAC_OPACTRL_OPA0HCMDIS))
| (init->shortInputs ? DAC_OPACTRL_OPA0SHORT : 0)
| (init->lpfPosPadDisable
? DAC_OPACTRL_OPA0LPFDIS_PLPFDIS : 0)
| (init->lpfNegPadDisable
? DAC_OPACTRL_OPA0LPFDIS_NLPFDIS : 0)
| (init->hcmDisable ? DAC_OPACTRL_OPA0HCMDIS : 0)
| DAC_OPACTRL_OPA0EN;
} else if ( opa == OPA1 ) {
EFM_ASSERT((init->outPen & ~_DAC_OPA1MUX_OUTPEN_MASK) == 0);
dac->BIASPROG = (dac->BIASPROG
& ~(_DAC_BIASPROG_BIASPROG_MASK
| DAC_BIASPROG_HALFBIAS))
| (init->bias << _DAC_BIASPROG_BIASPROG_SHIFT)
| (init->halfBias ? DAC_BIASPROG_HALFBIAS : 0);
if (init->defaultOffset) {
gain = dac->CAL & _DAC_CAL_GAIN_MASK;
SYSTEM_GetCalibrationValue(&dac->CAL);
dac->CAL = (dac->CAL & ~_DAC_CAL_GAIN_MASK) | gain;
} else {
EFM_ASSERT(init->offset <= (_DAC_CAL_CH1OFFSET_MASK
>> _DAC_CAL_CH1OFFSET_SHIFT));
dac->CAL = (dac->CAL & ~_DAC_CAL_CH1OFFSET_MASK)
| (init->offset << _DAC_CAL_CH1OFFSET_SHIFT);
}
dac->OPA1MUX = (uint32_t)init->resSel
| (uint32_t)init->outMode
| init->outPen
| (uint32_t)init->resInMux
| (uint32_t)init->negSel
| (uint32_t)init->posSel
| (init->nextOut ? DAC_OPA1MUX_NEXTOUT : 0)
| (init->npEn ? DAC_OPA1MUX_NPEN : 0)
| (init->ppEn ? DAC_OPA1MUX_PPEN : 0);
dac->CH1CTRL |= DAC_CH1CTRL_EN;
dac->OPACTRL = (dac->OPACTRL
& ~(DAC_OPACTRL_OPA1SHORT
| _DAC_OPACTRL_OPA1LPFDIS_MASK
| DAC_OPACTRL_OPA1HCMDIS))
| (init->shortInputs ? DAC_OPACTRL_OPA1SHORT : 0)
| (init->lpfPosPadDisable
? DAC_OPACTRL_OPA1LPFDIS_PLPFDIS : 0)
| (init->lpfNegPadDisable
? DAC_OPACTRL_OPA1LPFDIS_NLPFDIS : 0)
| (init->hcmDisable ? DAC_OPACTRL_OPA1HCMDIS : 0)
| DAC_OPACTRL_OPA1EN;
} else { /* OPA2 */
EFM_ASSERT((init->posSel == DAC_OPA2MUX_POSSEL_DISABLE)
|| (init->posSel == DAC_OPA2MUX_POSSEL_POSPAD)
|| (init->posSel == DAC_OPA2MUX_POSSEL_OPA1INP)
|| (init->posSel == DAC_OPA2MUX_POSSEL_OPATAP));
EFM_ASSERT((init->outMode & ~DAC_OPA2MUX_OUTMODE) == 0);
EFM_ASSERT((init->outPen & ~_DAC_OPA2MUX_OUTPEN_MASK) == 0);
dac->BIASPROG = (dac->BIASPROG
& ~(_DAC_BIASPROG_OPA2BIASPROG_MASK
| DAC_BIASPROG_OPA2HALFBIAS))
| (init->bias << _DAC_BIASPROG_OPA2BIASPROG_SHIFT)
| (init->halfBias ? DAC_BIASPROG_OPA2HALFBIAS : 0);
if (init->defaultOffset) {
SYSTEM_GetCalibrationValue(&dac->OPAOFFSET);
} else {
EFM_ASSERT(init->offset <= (_DAC_OPAOFFSET_OPA2OFFSET_MASK
>> _DAC_OPAOFFSET_OPA2OFFSET_SHIFT));
dac->OPAOFFSET = (dac->OPAOFFSET & ~_DAC_OPAOFFSET_OPA2OFFSET_MASK)
| (init->offset << _DAC_OPAOFFSET_OPA2OFFSET_SHIFT);
}
dac->OPA2MUX = (uint32_t)init->resSel
| (uint32_t)init->outMode
| init->outPen
| (uint32_t)init->resInMux
| (uint32_t)init->negSel
| (uint32_t)init->posSel
| (init->nextOut ? DAC_OPA2MUX_NEXTOUT : 0)
| (init->npEn ? DAC_OPA2MUX_NPEN : 0)
| (init->ppEn ? DAC_OPA2MUX_PPEN : 0);
dac->OPACTRL = (dac->OPACTRL
& ~(DAC_OPACTRL_OPA2SHORT
| _DAC_OPACTRL_OPA2LPFDIS_MASK
| DAC_OPACTRL_OPA2HCMDIS))
| (init->shortInputs ? DAC_OPACTRL_OPA2SHORT : 0)
| (init->lpfPosPadDisable
? DAC_OPACTRL_OPA2LPFDIS_PLPFDIS : 0)
| (init->lpfNegPadDisable
? DAC_OPACTRL_OPA2LPFDIS_NLPFDIS : 0)
| (init->hcmDisable ? DAC_OPACTRL_OPA2HCMDIS : 0)
| DAC_OPACTRL_OPA2EN;
}
#elif defined(_SILICON_LABS_32B_SERIES_1)
uint32_t calData = 0;
uint32_t warmupTime;
EFM_ASSERT(VDAC_REF_VALID(dac));
EFM_ASSERT(VDAC_OPA_VALID(opa));
EFM_ASSERT(init->settleTime <= (_VDAC_OPA_TIMER_SETTLETIME_MASK
>> _VDAC_OPA_TIMER_SETTLETIME_SHIFT));
EFM_ASSERT(init->startupDly <= (_VDAC_OPA_TIMER_STARTUPDLY_MASK
>> _VDAC_OPA_TIMER_STARTUPDLY_SHIFT));
EFM_ASSERT((init->outPen & ~_VDAC_OPA_OUT_ALTOUTPADEN_MASK) == 0);
EFM_ASSERT((init->drvStr == opaDrvStrLowerAccLowStr)
|| (init->drvStr == opaDrvStrLowAccLowStr)
|| (init->drvStr == opaDrvStrHighAccHighStr)
|| (init->drvStr == opaDrvStrHigherAccHighStr));
/* Disable OPAMP before writing to registers. */
OPAMP_Disable(dac, opa);
/* Get the calibration value based on OPAMP, Drive Strength, and INCBW. */
switch (opa) {
#if defined(VDAC_STATUS_OPA0ENS)
case OPA0:
switch (init->drvStr) {
case opaDrvStrLowerAccLowStr:
calData = (init->ugBwScale ? DEVINFO->OPA0CAL0 : DEVINFO->OPA0CAL4);
break;
case opaDrvStrLowAccLowStr:
calData = (init->ugBwScale ? DEVINFO->OPA0CAL1 : DEVINFO->OPA0CAL5);
break;
case opaDrvStrHighAccHighStr:
calData = (init->ugBwScale ? DEVINFO->OPA0CAL2 : DEVINFO->OPA0CAL6);
break;
case opaDrvStrHigherAccHighStr:
calData = (init->ugBwScale ? DEVINFO->OPA0CAL3 : DEVINFO->OPA0CAL7);
break;
}
break;
#endif
#if defined(VDAC_STATUS_OPA1ENS)
case OPA1:
switch (init->drvStr) {
case opaDrvStrLowerAccLowStr:
calData = (init->ugBwScale ? DEVINFO->OPA1CAL0 : DEVINFO->OPA1CAL4);
break;
case opaDrvStrLowAccLowStr:
calData = (init->ugBwScale ? DEVINFO->OPA1CAL1 : DEVINFO->OPA1CAL5);
break;
case opaDrvStrHighAccHighStr:
calData = (init->ugBwScale ? DEVINFO->OPA1CAL2 : DEVINFO->OPA1CAL6);
break;
case opaDrvStrHigherAccHighStr:
calData = (init->ugBwScale ? DEVINFO->OPA1CAL3 : DEVINFO->OPA1CAL7);
break;
}
break;
#endif
#if defined(VDAC_STATUS_OPA2ENS)
case OPA2:
switch (init->drvStr) {
case opaDrvStrLowerAccLowStr:
calData = (init->ugBwScale ? DEVINFO->OPA2CAL0 : DEVINFO->OPA2CAL4);
break;
case opaDrvStrLowAccLowStr:
calData = (init->ugBwScale ? DEVINFO->OPA2CAL1 : DEVINFO->OPA2CAL5);
break;
case opaDrvStrHighAccHighStr:
calData = (init->ugBwScale ? DEVINFO->OPA2CAL2 : DEVINFO->OPA2CAL6);
break;
case opaDrvStrHigherAccHighStr:
calData = (init->ugBwScale ? DEVINFO->OPA2CAL3 : DEVINFO->OPA2CAL7);
break;
}
break;
#endif
#if defined(VDAC_STATUS_OPA3ENS)
case OPA3:
switch (init->drvStr) {
case opaDrvStrLowerAccLowStr:
calData = (init->ugBwScale ? DEVINFO->OPA3CAL0 : DEVINFO->OPA3CAL4);
break;
case opaDrvStrLowAccLowStr:
calData = (init->ugBwScale ? DEVINFO->OPA3CAL1 : DEVINFO->OPA3CAL5);
break;
case opaDrvStrHighAccHighStr:
calData = (init->ugBwScale ? DEVINFO->OPA3CAL2 : DEVINFO->OPA3CAL6);
break;
case opaDrvStrHigherAccHighStr:
calData = (init->ugBwScale ? DEVINFO->OPA3CAL3 : DEVINFO->OPA3CAL7);
break;
}
break;
#endif
}
if (!init->defaultOffsetN) {
EFM_ASSERT(init->offsetN <= (_VDAC_OPA_CAL_OFFSETN_MASK
>> _VDAC_OPA_CAL_OFFSETN_SHIFT));
calData = (calData & ~_VDAC_OPA_CAL_OFFSETN_MASK)
| (init->offsetN << _VDAC_OPA_CAL_OFFSETN_SHIFT);
}
if (!init->defaultOffsetP) {
EFM_ASSERT(init->offsetP <= (_VDAC_OPA_CAL_OFFSETP_MASK
>> _VDAC_OPA_CAL_OFFSETP_SHIFT));
calData = (calData & ~_VDAC_OPA_CAL_OFFSETP_MASK)
| (init->offsetP << _VDAC_OPA_CAL_OFFSETP_SHIFT);
}
dac->OPA[opa].CAL = (calData & _VDAC_OPA_CAL_MASK);
dac->OPA[opa].MUX = (uint32_t)init->resSel
| (init->gain3xEn ? VDAC_OPA_MUX_GAIN3X : 0)
| (uint32_t)init->resInMux
| (uint32_t)init->negSel
| (uint32_t)init->posSel;
dac->OPA[opa].OUT = (uint32_t)init->outMode
| (uint32_t)init->outPen;
switch (init->drvStr) {
case opaDrvStrHigherAccHighStr:
warmupTime = 6;
break;
case opaDrvStrHighAccHighStr:
warmupTime = 8;
break;
case opaDrvStrLowAccLowStr:
warmupTime = 85;
break;
case opaDrvStrLowerAccLowStr:
default:
warmupTime = 100;
break;
}
dac->OPA[opa].TIMER = (uint32_t)(init->settleTime
<< _VDAC_OPA_TIMER_SETTLETIME_SHIFT)
| (uint32_t)(warmupTime
<< _VDAC_OPA_TIMER_WARMUPTIME_SHIFT)
| (uint32_t)(init->startupDly
<< _VDAC_OPA_TIMER_STARTUPDLY_SHIFT);
dac->OPA[opa].CTRL = (init->aportYMasterDisable
? VDAC_OPA_CTRL_APORTYMASTERDIS : 0)
| (init->aportXMasterDisable
? VDAC_OPA_CTRL_APORTXMASTERDIS : 0)
| (uint32_t)init->prsOutSel
| (uint32_t)init->prsSel
| (uint32_t)init->prsMode
| (init->prsEn ? VDAC_OPA_CTRL_PRSEN : 0)
| (init->halfDrvStr
? VDAC_OPA_CTRL_OUTSCALE_HALF
: VDAC_OPA_CTRL_OUTSCALE_FULL)
| (init->hcmDisable ? VDAC_OPA_CTRL_HCMDIS : 0)
| (init->ugBwScale ? VDAC_OPA_CTRL_INCBW : 0)
| (uint32_t)init->drvStr;
if (opa == OPA0) {
#if defined(VDAC_STATUS_OPA0ENS)
dac->CMD |= VDAC_CMD_OPA0EN;
#endif
#if defined(VDAC_STATUS_OPA1ENS)
} else if (opa == OPA1) {
dac->CMD |= VDAC_CMD_OPA1EN;
#endif
#if defined(VDAC_STATUS_OPA2ENS)
} else if (opa == OPA2) {
dac->CMD |= VDAC_CMD_OPA2EN;
#endif
#if defined(VDAC_STATUS_OPA3ENS)
} else { /* OPA3 */
dac->CMD |= VDAC_CMD_OPA3EN;
#endif
}
#endif
}
/** @} (end addtogroup opamp) */
#endif /* (defined(OPAMP_PRESENT) && (OPAMP_COUNT == 1)
|| defined(VDAC_PRESENT) && (VDAC_COUNT > 0) */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,661 @@
/***************************************************************************//**
* @file
* @brief Peripheral Reflex System (PRS) Peripheral API
*******************************************************************************
* # License
* <b>Copyright 2018 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* 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_prs.h"
#if defined(PRS_COUNT) && (PRS_COUNT > 0)
#include "sl_assert.h"
/***************************************************************************//**
* @addtogroup prs PRS - Peripheral Reflex System
* @brief Peripheral Reflex System (PRS) Peripheral API
* @details
* This module contains functions to control the PRS peripheral of Silicon
* Labs 32-bit MCUs and SoCs. The PRS allows configurable, fast, and autonomous
* communication between peripherals on the MCU or SoC.
* @{
******************************************************************************/
/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
/*******************************************************************************
******************************* DEFINES ***********************************
******************************************************************************/
/* Generic defines for async and sync signals applying to all TIMER instances.
* Those defines map to TIMER2 but it could be any TIMER instance number. */
#define _PRS_ASYNC_CH_CTRL_SIGSEL_TIMERUF _PRS_ASYNC_CH_CTRL_SIGSEL_TIMER2UF
#define _PRS_ASYNC_CH_CTRL_SIGSEL_TIMEROF _PRS_ASYNC_CH_CTRL_SIGSEL_TIMER2OF
#define _PRS_ASYNC_CH_CTRL_SIGSEL_TIMERCC0 _PRS_ASYNC_CH_CTRL_SIGSEL_TIMER2CC0
#define _PRS_ASYNC_CH_CTRL_SIGSEL_TIMERCC1 _PRS_ASYNC_CH_CTRL_SIGSEL_TIMER2CC1
#define _PRS_ASYNC_CH_CTRL_SIGSEL_TIMERCC2 _PRS_ASYNC_CH_CTRL_SIGSEL_TIMER2CC2
#define _PRS_SYNC_CH_CTRL_SIGSEL_TIMERUF _PRS_SYNC_CH_CTRL_SIGSEL_TIMER2UF
#define _PRS_SYNC_CH_CTRL_SIGSEL_TIMEROF _PRS_SYNC_CH_CTRL_SIGSEL_TIMER2OF
#define _PRS_SYNC_CH_CTRL_SIGSEL_TIMERCC0 _PRS_SYNC_CH_CTRL_SIGSEL_TIMER2CC0
#define _PRS_SYNC_CH_CTRL_SIGSEL_TIMERCC1 _PRS_SYNC_CH_CTRL_SIGSEL_TIMER2CC1
#define _PRS_SYNC_CH_CTRL_SIGSEL_TIMERCC2 _PRS_SYNC_CH_CTRL_SIGSEL_TIMER2CC2
/*******************************************************************************
************************** LOCAL FUNCTIONS ********************************
******************************************************************************/
/***************************************************************************//**
* @brief
* Get PRS source signal for a channel.
*
* @param[in] type
* PRS channel type. This can be either @ref prsTypeAsync or
* @ref prsTypeSync.
*
* @param[in] ch
* channel number.
*
* @return
* PRS signal assigned to the channel.
******************************************************************************/
static PRS_Signal_t getSignal(unsigned int ch, PRS_ChType_t type)
{
PRS_Signal_t signal;
#if defined(_PRS_ASYNC_CH_CTRL_SOURCESEL_MASK)
if (type == prsTypeAsync) {
signal = (PRS_Signal_t) (PRS->ASYNC_CH[ch].CTRL
& (_PRS_ASYNC_CH_CTRL_SOURCESEL_MASK | _PRS_ASYNC_CH_CTRL_SIGSEL_MASK));
} else {
signal = (PRS_Signal_t) (PRS->SYNC_CH[ch].CTRL
& (_PRS_SYNC_CH_CTRL_SOURCESEL_MASK | _PRS_SYNC_CH_CTRL_SIGSEL_MASK));
}
#else
(void) type;
signal = (PRS_Signal_t) (PRS->CH[ch].CTRL
& (_PRS_CH_CTRL_SOURCESEL_MASK | _PRS_CH_CTRL_SIGSEL_MASK));
#endif
return signal;
}
/** @endcond */
/*******************************************************************************
************************** GLOBAL FUNCTIONS *******************************
******************************************************************************/
#if defined(_SILICON_LABS_32B_SERIES_2)
/***************************************************************************//**
* @brief
* Convert an async PRS source to a sync source.
*
* @details
* This conversion must be done because the id's of the same peripheral
* source is different depending on if it's used as an asynchronous PRS source
* or a synchronous PRS source.
*
* @param[in] asyncSource
* The id of the asynchronous PRS source.
*
* @return
* The id of the corresponding synchronous PRS source.
******************************************************************************/
uint32_t PRS_ConvertToSyncSource(uint32_t asyncSource)
{
uint32_t syncSource = 0;
switch (asyncSource) {
case _PRS_ASYNC_CH_CTRL_SOURCESEL_NONE:
syncSource = _PRS_SYNC_CH_CTRL_SOURCESEL_NONE;
break;
#if defined(IADC_PRESENT)
case _PRS_ASYNC_CH_CTRL_SOURCESEL_IADC0:
syncSource = _PRS_SYNC_CH_CTRL_SOURCESEL_IADC0;
break;
#endif
case _PRS_ASYNC_CH_CTRL_SOURCESEL_TIMER0:
syncSource = _PRS_SYNC_CH_CTRL_SOURCESEL_TIMER0;
break;
case _PRS_ASYNC_CH_CTRL_SOURCESEL_TIMER1:
syncSource = _PRS_SYNC_CH_CTRL_SOURCESEL_TIMER1;
break;
case _PRS_ASYNC_CH_CTRL_SOURCESEL_TIMER2:
syncSource = _PRS_SYNC_CH_CTRL_SOURCESEL_TIMER2;
break;
case _PRS_ASYNC_CH_CTRL_SOURCESEL_TIMER3:
syncSource = _PRS_SYNC_CH_CTRL_SOURCESEL_TIMER3;
break;
#if defined(TIMER4)
case _PRS_ASYNC_CH_CTRL_SOURCESEL_TIMER4:
syncSource = _PRS_SYNC_CH_CTRL_SOURCESEL_TIMER4;
break;
#endif
#if defined(TIMER5)
case _PRS_ASYNC_CH_CTRL_SOURCESEL_TIMER5:
syncSource = _PRS_SYNC_CH_CTRL_SOURCESEL_TIMER5;
break;
#endif
#if defined(TIMER6)
case _PRS_ASYNC_CH_CTRL_SOURCESEL_TIMER6:
syncSource = _PRS_SYNC_CH_CTRL_SOURCESEL_TIMER6;
break;
#endif
#if defined(TIMER7)
case _PRS_ASYNC_CH_CTRL_SOURCESEL_TIMER7:
syncSource = _PRS_SYNC_CH_CTRL_SOURCESEL_TIMER7;
break;
#endif
#if defined(VDAC0)
case _PRS_ASYNC_CH_CTRL_SOURCESEL_VDAC0L:
syncSource = _PRS_SYNC_CH_CTRL_SOURCESEL_VDAC0;
break;
#endif
#if defined(VDAC1)
case _PRS_ASYNC_CH_CTRL_SOURCESEL_VDAC1L:
syncSource = _PRS_SYNC_CH_CTRL_SOURCESEL_VDAC1;
break;
#endif
default:
EFM_ASSERT(false);
break;
}
return syncSource;
}
/***************************************************************************//**
* @brief
* Convert an async PRS signal to a sync signal.
*
* @details
* PRS values for some peripherals signals differ between asynchronous and
* synchronous PRS channels. This function must be used to handle the
* conversion.
*
* @param[in] asyncSource
* The id of the asynchronous PRS source.
*
* @param[in] asyncSignal
* The id of the asynchronous PRS signal.
*
* @return
* The id of the corresponding synchronous PRS signal.
******************************************************************************/
uint32_t PRS_ConvertToSyncSignal(uint32_t asyncSource, uint32_t asyncSignal)
{
uint32_t syncSignal = asyncSignal;
switch (asyncSource) {
case _PRS_ASYNC_CH_CTRL_SOURCESEL_TIMER0:
case _PRS_ASYNC_CH_CTRL_SOURCESEL_TIMER1:
case _PRS_ASYNC_CH_CTRL_SOURCESEL_TIMER2:
case _PRS_ASYNC_CH_CTRL_SOURCESEL_TIMER3:
#if defined(_PRS_ASYNC_CH_CTRL_SOURCESEL_TIMER4)
case _PRS_ASYNC_CH_CTRL_SOURCESEL_TIMER4:
#endif
#if defined(_PRS_ASYNC_CH_CTRL_SOURCESEL_TIMER5)
case _PRS_ASYNC_CH_CTRL_SOURCESEL_TIMER5:
#endif
#if defined(_PRS_ASYNC_CH_CTRL_SOURCESEL_TIMER6)
case _PRS_ASYNC_CH_CTRL_SOURCESEL_TIMER6:
#endif
#if defined(_PRS_ASYNC_CH_CTRL_SOURCESEL_TIMER7)
case _PRS_ASYNC_CH_CTRL_SOURCESEL_TIMER7:
#endif
/* Async and sync signal values are consistent across all timers instances.
* Generic defines are used. */
switch (asyncSignal) {
case _PRS_ASYNC_CH_CTRL_SIGSEL_TIMERUF:
syncSignal = _PRS_SYNC_CH_CTRL_SIGSEL_TIMERUF;
break;
case _PRS_ASYNC_CH_CTRL_SIGSEL_TIMEROF:
syncSignal = _PRS_SYNC_CH_CTRL_SIGSEL_TIMEROF;
break;
case _PRS_ASYNC_CH_CTRL_SIGSEL_TIMERCC0:
syncSignal = _PRS_SYNC_CH_CTRL_SIGSEL_TIMERCC0;
break;
case _PRS_ASYNC_CH_CTRL_SIGSEL_TIMERCC1:
syncSignal = _PRS_SYNC_CH_CTRL_SIGSEL_TIMERCC1;
break;
case _PRS_ASYNC_CH_CTRL_SIGSEL_TIMERCC2:
syncSignal = _PRS_SYNC_CH_CTRL_SIGSEL_TIMERCC2;
break;
default:
EFM_ASSERT(false);
break;
}
break;
#if defined(IADC0)
case _PRS_ASYNC_CH_CTRL_SOURCESEL_IADC0:
switch (asyncSignal) {
case _PRS_ASYNC_CH_CTRL_SIGSEL_IADC0SCANENTRYDONE:
syncSignal = _PRS_SYNC_CH_CTRL_SIGSEL_IADC0SCANENTRYDONE;
break;
case _PRS_ASYNC_CH_CTRL_SIGSEL_IADC0SCANTABLEDONE:
syncSignal = _PRS_SYNC_CH_CTRL_SIGSEL_IADC0SCANTABLEDONE;
break;
case _PRS_ASYNC_CH_CTRL_SIGSEL_IADC0SINGLEDONE:
syncSignal = _PRS_SYNC_CH_CTRL_SIGSEL_IADC0SINGLEDONE;
break;
default:
EFM_ASSERT(false);
break;
}
break;
#endif
#if defined(VDAC0)
case _PRS_ASYNC_CH_CTRL_SOURCESEL_VDAC0L:
switch (asyncSignal) {
case _PRS_ASYNC_CH_CTRL_SIGSEL_VDAC0LCH0DONEASYNC:
syncSignal = _PRS_SYNC_CH_CTRL_SIGSEL_VDAC0CH0DONESYNC;
break;
case _PRS_ASYNC_CH_CTRL_SIGSEL_VDAC0LCH1DONEASYNC:
syncSignal = _PRS_SYNC_CH_CTRL_SIGSEL_VDAC0CH1DONESYNC;
break;
default:
EFM_ASSERT(false);
break;
}
break;
#endif
#if defined(VDAC1)
case _PRS_ASYNC_CH_CTRL_SOURCESEL_VDAC1L:
switch (asyncSignal) {
case _PRS_ASYNC_CH_CTRL_SIGSEL_VDAC1LCH0DONEASYNC:
syncSignal = _PRS_SYNC_CH_CTRL_SIGSEL_VDAC1CH0DONESYNC;
break;
case _PRS_ASYNC_CH_CTRL_SIGSEL_VDAC1LCH1DONEASYNC:
syncSignal = _PRS_SYNC_CH_CTRL_SIGSEL_VDAC1CH1DONESYNC;
break;
default:
EFM_ASSERT(false);
break;
}
break;
#endif
default:
// No translation
break;
}
return syncSignal;
}
#endif
/***************************************************************************//**
* @brief
* Set a source and signal for a channel.
*
* @param[in] ch
* A channel to define the signal and source for.
*
* @param[in] source
* A source to select for the channel. Use one of PRS_CH_CTRL_SOURCESEL_x defines.
*
* @param[in] signal
* A signal (for selected @p source) to use. Use one of PRS_CH_CTRL_SIGSEL_x
* defines.
*
* @param[in] edge
* An edge (for selected source/signal) to generate the pulse for.
******************************************************************************/
void PRS_SourceSignalSet(unsigned int ch,
uint32_t source,
uint32_t signal,
PRS_Edge_TypeDef edge)
{
#if defined(_PRS_SYNC_CH_CTRL_MASK)
(void) edge;
EFM_ASSERT(ch < PRS_SYNC_CHAN_COUNT);
PRS->SYNC_CH[ch].CTRL = (source & _PRS_SYNC_CH_CTRL_SOURCESEL_MASK)
| (signal & _PRS_SYNC_CH_CTRL_SIGSEL_MASK);
#else
EFM_ASSERT(ch < PRS_CHAN_COUNT);
PRS->CH[ch].CTRL = (source & _PRS_CH_CTRL_SOURCESEL_MASK)
| (signal & _PRS_CH_CTRL_SIGSEL_MASK)
| (uint32_t)edge << _PRS_CH_CTRL_EDSEL_SHIFT;
#endif
}
#if defined(PRS_ASYNC_SUPPORTED)
/***************************************************************************//**
* @brief
* Set the source and asynchronous signal for a channel.
*
* @details
* Asynchronous reflexes are not clocked on HFPERCLK and can be used even in
* EM2/EM3.
* There is a limitation to reflexes operating in asynchronous mode in
* that they can only be used by a subset of the reflex consumers. See
* the PRS chapter in the reference manual for the complete list of
* supported asynchronous signals and consumers.
*
* @note
* This function is not supported on EFM32GxxxFyyy parts.
* In asynchronous mode, the edge detector only works in EM0 and should
* not be used. The EDSEL parameter in PRS_CHx_CTRL register is set to 0 (OFF)
* by default.
*
* @param[in] ch
* A channel to define the source and asynchronous signal for.
*
* @param[in] source
* A source to select for the channel. Use one of PRS_CH_CTRL_SOURCESEL_x defines.
*
* @param[in] signal
* An asynchronous signal (for selected @p source) to use. Use one of the
* PRS_CH_CTRL_SIGSEL_x defines that support asynchronous operation.
******************************************************************************/
SL_WEAK void PRS_SourceAsyncSignalSet(unsigned int ch,
uint32_t source,
uint32_t signal)
{
PRS_ConnectSignal(ch, prsTypeAsync, (PRS_Signal_t) (source | signal));
}
#endif
#if defined(_PRS_ROUTELOC0_MASK) || (defined(_PRS_ROUTE_MASK) && (_PRS_ROUTE_MASK))
/***************************************************************************//**
* @brief
* Send the output of a PRS channel to a GPIO pin.
*
* @details
* This function is used to send the output of a PRS channel to a GPIO pin.
* Note that there are certain restrictions to where a PRS channel can be
* routed. Consult the datasheet of the device to see if a channel can be
* routed to the requested GPIO pin.
*
* @param[in] ch
* PRS channel number.
*
* @param[in] location
* PRS routing location.
******************************************************************************/
void PRS_GpioOutputLocation(unsigned int ch,
unsigned int location)
{
EFM_ASSERT(ch < PRS_CHAN_COUNT);
#if defined(_PRS_ROUTE_MASK)
PRS->ROUTE |= (location << _PRS_ROUTE_LOCATION_SHIFT)
| (1 << ch);
#else
uint32_t shift = (ch % 4) * 8;
uint32_t mask = location << shift;
uint32_t locationGroup = ch / 4;
/* Since all ROUTELOCx registers are in consecutive memory locations, treat them
* as an array starting at ROUTELOC0 and use locationGroup to index into this array */
volatile uint32_t * routeloc = &PRS->ROUTELOC0;
routeloc[locationGroup] |= mask;
PRS->ROUTEPEN |= 1 << ch;
#endif
}
#endif
/***************************************************************************//**
* @brief
* Search for the first free PRS channel.
*
* @param[in] type
* PRS channel type. This can be either @ref prsTypeAsync or
* @ref prsTypeSync.
*
* @return
* Channel number >= 0 if an unused PRS channel was found. If no free PRS
* channel was found then -1 is returned.
******************************************************************************/
SL_WEAK int PRS_GetFreeChannel(PRS_ChType_t type)
{
int ch = -1;
PRS_Signal_t signal;
int max;
if (type == prsTypeAsync) {
max = PRS_ASYNC_CHAN_COUNT;
} else {
max = PRS_SYNC_CHAN_COUNT;
}
for (int i = 0; i < max; i++) {
signal = getSignal(i, type);
if (signal == prsSignalNone) {
ch = i;
break;
}
}
return ch;
}
/***************************************************************************//**
* @brief
* Reset all PRS channels
*
* @details
* This function will reset all the PRS channel configuration.
******************************************************************************/
void PRS_Reset(void)
{
unsigned int i;
#if defined(_SILICON_LABS_32B_SERIES_2)
PRS->ASYNC_SWLEVEL = 0;
for (i = 0; i < PRS_ASYNC_CHAN_COUNT; i++) {
PRS->ASYNC_CH[i].CTRL = _PRS_ASYNC_CH_CTRL_RESETVALUE;
}
for (i = 0; i < PRS_SYNC_CHAN_COUNT; i++) {
PRS->SYNC_CH[i].CTRL = _PRS_SYNC_CH_CTRL_RESETVALUE;
}
#else
PRS->SWLEVEL = 0x0;
for (i = 0; i < PRS_CHAN_COUNT; i++) {
PRS->CH[i].CTRL = _PRS_CH_CTRL_RESETVALUE;
}
#endif
}
/***************************************************************************//**
* @brief
* Connect a PRS signal to a channel.
*
* @details
* This function will make the PRS signal available on the specific channel.
* Only a single PRS signal can be connected to any given channel.
*
* @param[in] ch
* PRS channel number.
*
* @param[in] type
* PRS channel type. This can be either @ref prsTypeAsync or
* @ref prsTypeSync.
*
* @param[in] signal
* This is the PRS signal that should be placed on the channel.
******************************************************************************/
void PRS_ConnectSignal(unsigned int ch, PRS_ChType_t type, PRS_Signal_t signal)
{
#if defined(_PRS_ASYNC_CH_CTRL_MASK)
// Series 2 devices
uint32_t sourceField = ((uint32_t)signal & _PRS_ASYNC_CH_CTRL_SOURCESEL_MASK)
>> _PRS_ASYNC_CH_CTRL_SOURCESEL_SHIFT;
uint32_t signalField = ((uint32_t)signal & _PRS_ASYNC_CH_CTRL_SIGSEL_MASK)
>> _PRS_ASYNC_CH_CTRL_SIGSEL_SHIFT;
if (type == prsTypeAsync) {
EFM_ASSERT(ch < PRS_ASYNC_CHAN_COUNT);
PRS->ASYNC_CH[ch].CTRL = PRS_ASYNC_CH_CTRL_FNSEL_A
| (sourceField << _PRS_ASYNC_CH_CTRL_SOURCESEL_SHIFT)
| (signalField << _PRS_ASYNC_CH_CTRL_SIGSEL_SHIFT);
} else {
EFM_ASSERT(ch < PRS_SYNC_CHAN_COUNT);
signalField = PRS_ConvertToSyncSignal(sourceField, signalField);
sourceField = PRS_ConvertToSyncSource(sourceField);
PRS->SYNC_CH[ch].CTRL = (sourceField << _PRS_SYNC_CH_CTRL_SOURCESEL_SHIFT)
| (signalField << _PRS_SYNC_CH_CTRL_SIGSEL_SHIFT);
}
#else
// Series 0 and Series 1 devices
uint32_t signalField = (uint32_t) signal & (_PRS_CH_CTRL_SOURCESEL_MASK
| _PRS_CH_CTRL_SIGSEL_MASK);
if (type == prsTypeAsync) {
#if defined(PRS_ASYNC_SUPPORTED)
EFM_ASSERT(ch < PRS_ASYNC_CHAN_COUNT);
PRS->CH[ch].CTRL = PRS_CH_CTRL_EDSEL_OFF
| PRS_CH_CTRL_ASYNC
| signalField;
#endif
} else {
EFM_ASSERT(ch < PRS_SYNC_CHAN_COUNT);
PRS->CH[ch].CTRL = PRS_CH_CTRL_EDSEL_OFF
| signalField;
}
#endif
}
#if defined(_SILICON_LABS_32B_SERIES_2)
/***************************************************************************//**
* @brief
* Connect a peripheral consumer to a PRS channel.
*
* @details
* Different peripherals can use PRS channels as their input. This function
* can be used to connect a peripheral consumer to a PRS channel. Multiple
* consumers can be connected to a single PRS channel.
*
* @param[in] ch
* PRS channel number.
*
* @param[in] type
* PRS channel type. This can be either @ref prsTypeAsync or
* @ref prsTypeSync.
*
* @param[in] consumer
* This is the PRS consumer.
******************************************************************************/
SL_WEAK void PRS_ConnectConsumer(unsigned int ch, PRS_ChType_t type, PRS_Consumer_t consumer)
{
EFM_ASSERT((uint32_t)consumer <= 0xFFF);
volatile uint32_t * addr = (volatile uint32_t *) PRS;
uint32_t offset = (uint32_t) consumer;
addr = addr + offset / 4;
if (consumer != prsConsumerNone) {
if (type == prsTypeAsync) {
*addr = ch << _PRS_CONSUMER_TIMER0_CC0_PRSSEL_SHIFT;
} else {
*addr = ch << _PRS_CONSUMER_TIMER0_CC0_SPRSSEL_SHIFT;
}
}
}
/***************************************************************************//**
* @brief
* Send the output of a PRS channel to a GPIO pin.
*
* @details
* This function is used to send the output of a PRS channel to a GPIO pin.
* Note that there are certain restrictions to where a PRS channel can be
* routed. Consult the datasheet of the device to see if a channel can be
* routed to the requested GPIO pin. Some devices for instance can only route
* the async channels 0-5 on GPIO pins PAx and PBx while async channels 6-11
* can only be routed to GPIO pins PCx and PDx
*
* @param[in] ch
* PRS channel number.
*
* @param[in] type
* PRS channel type. This can be either @ref prsTypeAsync or
* @ref prsTypeSync.
*
* @param[in] port
* GPIO port
*
* @param[in] pin
* GPIO pin
******************************************************************************/
SL_WEAK void PRS_PinOutput(unsigned int ch, PRS_ChType_t type, GPIO_Port_TypeDef port, uint8_t pin)
{
volatile uint32_t * addr;
if (type == prsTypeAsync) {
addr = &GPIO->PRSROUTE[0].ASYNCH0ROUTE;
} else {
addr = &GPIO->PRSROUTE[0].SYNCH0ROUTE;
}
addr += ch;
*addr = ((uint32_t)port << _GPIO_PRS_ASYNCH0ROUTE_PORT_SHIFT)
| ((uint32_t)pin << _GPIO_PRS_ASYNCH0ROUTE_PIN_SHIFT);
if (type == prsTypeAsync) {
GPIO->PRSROUTE[0].ROUTEEN |= 0x1 << (ch + _GPIO_PRS_ROUTEEN_ASYNCH0PEN_SHIFT);
} else {
GPIO->PRSROUTE[0].ROUTEEN |= 0x1 << (ch + _GPIO_PRS_ROUTEEN_SYNCH0PEN_SHIFT);
}
}
/***************************************************************************//**
* @brief
* Combine two PRS channels using a logic function.
*
* @details
* This function allows you to combine the output of one PRS channel with the
* the signal of another PRS channel using various logic functions. Note that
* for series 2, config 1 devices, the hardware only allows a PRS channel to
* be combined with the previous channel. So for instance channel 5 can be
* combined only with channel 4.
*
* The logic function operates on two PRS channels called A and B. The output
* of PRS channel B is combined with the PRS source configured for channel A
* to produce an output. This output is used as the output of channel A.
*
* @param[in] chA
* PRS Channel for the A input.
*
* @param[in] chB
* PRS Channel for the B input.
*
* @param[in] logic
* The logic function to use when combining the Channel A and Channel B. The
* output of the logic function is the output of Channel A. Function like
* AND, OR, XOR, NOT and more are available.
******************************************************************************/
SL_WEAK void PRS_Combine(unsigned int chA, unsigned int chB, PRS_Logic_t logic)
{
EFM_ASSERT(chA < PRS_ASYNC_CHAN_COUNT);
EFM_ASSERT(chB < PRS_ASYNC_CHAN_COUNT);
#if defined(_SILICON_LABS_32B_SERIES_2_CONFIG_1)
EFM_ASSERT(chA == ((chB + 1) % PRS_ASYNC_CHAN_COUNT));
PRS->ASYNC_CH[chA].CTRL = (PRS->ASYNC_CH[chA].CTRL & ~_PRS_ASYNC_CH_CTRL_FNSEL_MASK)
| ((uint32_t)logic << _PRS_ASYNC_CH_CTRL_FNSEL_SHIFT);
#else
PRS->ASYNC_CH[chA].CTRL = (PRS->ASYNC_CH[chA].CTRL
& ~(_PRS_ASYNC_CH_CTRL_FNSEL_MASK
| _PRS_ASYNC_CH_CTRL_AUXSEL_MASK))
| ((uint32_t)logic << _PRS_ASYNC_CH_CTRL_FNSEL_SHIFT)
| ((uint32_t)chB << _PRS_ASYNC_CH_CTRL_AUXSEL_SHIFT);
#endif
}
#endif
/** @} (end addtogroup prs) */
#endif /* defined(PRS_COUNT) && (PRS_COUNT > 0) */

View File

@@ -0,0 +1,402 @@
/***************************************************************************//**
* @file
* @brief Reset Management Unit (RMU) peripheral module peripheral API
*******************************************************************************
* # License
* <b>Copyright 2018 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* 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_rmu.h"
#if (defined(RMU_COUNT) && (RMU_COUNT > 0)) || (_EMU_RSTCTRL_MASK)
#include "sl_common.h"
#include "em_emu.h"
#include "em_bus.h"
/***************************************************************************//**
* @addtogroup rmu RMU - Reset Management Unit
* @brief Reset Management Unit (RMU) Peripheral API
* @details
* This module contains functions to control the RMU peripheral of Silicon
* Labs 32-bit MCUs and SoCs. RMU ensures correct reset operation and is
* responsible for connecting the different reset sources to the reset lines of
* the MCU or SoC.
* @{
******************************************************************************/
/*******************************************************************************
***************************** DEFINES *********************************
******************************************************************************/
/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
#if defined(_RMU_RSTCAUSE_MASK)
/** Reset cause XMASKS for series-0 and series-1 devices.
Reset cause zero and "don't care" bit definitions (XMASKs).
An XMASK 1 bit marks a bit that must be zero in RMU_RSTCAUSE. A 0 in XMASK
is a "don't care" bit in RMU_RSTCAUSE if also 0 in resetCauseMask
in @ref RMU_ResetCauseMasks_Typedef. */
/* EFM32G */
#if (_RMU_RSTCAUSE_MASK == 0x0000007FUL)
#define RMU_RSTCAUSE_PORST_XMASK 0x00000000UL /** 0000000000000000 < Power On Reset */
#define RMU_RSTCAUSE_BODUNREGRST_XMASK 0x00000001UL /** 0000000000000001 < Brown Out Detector Unregulated Domain Reset */
#define RMU_RSTCAUSE_BODREGRST_XMASK 0x0000001BUL /** 0000000000011011 < Brown Out Detector Regulated Domain Reset */
#define RMU_RSTCAUSE_EXTRST_XMASK 0x00000003UL /** 0000000000000011 < External Pin Reset */
#define RMU_RSTCAUSE_WDOGRST_XMASK 0x00000003UL /** 0000000000000011 < Watchdog Reset */
#define RMU_RSTCAUSE_LOCKUPRST_XMASK 0x0000001FUL /** 0000000000011111 < LOCKUP Reset */
#define RMU_RSTCAUSE_SYSREQRST_XMASK 0x0000001FUL /** 0000000000011111 < System Request Reset */
#define NUM_RSTCAUSES 7
/* EFM32TG, EFM32HG, EZR32HG, EFM32ZG */
#elif (_RMU_RSTCAUSE_MASK == 0x000007FFUL)
#define RMU_RSTCAUSE_PORST_XMASK 0x00000000UL /** 0000000000000000 < Power On Reset */
#define RMU_RSTCAUSE_BODUNREGRST_XMASK 0x00000081UL /** 0000000010000001 < Brown Out Detector Unregulated Domain Reset */
#define RMU_RSTCAUSE_BODREGRST_XMASK 0x00000091UL /** 0000000010010001 < Brown Out Detector Regulated Domain Reset */
#define RMU_RSTCAUSE_EXTRST_XMASK 0x00000001UL /** 0000000000000001 < External Pin Reset */
#define RMU_RSTCAUSE_WDOGRST_XMASK 0x00000003UL /** 0000000000000011 < Watchdog Reset */
#define RMU_RSTCAUSE_LOCKUPRST_XMASK 0x0000EFDFUL /** 1110111111011111 < LOCKUP Reset */
#define RMU_RSTCAUSE_SYSREQRST_XMASK 0x0000EF9FUL /** 1110111110011111 < System Request Reset */
#define RMU_RSTCAUSE_EM4RST_XMASK 0x00000719UL /** 0000011100011001 < EM4 Reset */
#define RMU_RSTCAUSE_EM4WURST_XMASK 0x00000619UL /** 0000011000011001 < EM4 Wake-up Reset */
#define RMU_RSTCAUSE_BODAVDD0_XMASK 0x0000041FUL /** 0000010000011111 < AVDD0 Bod Reset. */
#define RMU_RSTCAUSE_BODAVDD1_XMASK 0x0000021FUL /** 0000001000011111 < AVDD1 Bod Reset. */
#define NUM_RSTCAUSES 11
/* EFM32GG, EFM32LG, EZR32LG, EFM32WG, EZR32WG */
#elif (_RMU_RSTCAUSE_MASK == 0x0000FFFFUL)
#define RMU_RSTCAUSE_PORST_XMASK 0x00000000UL /** 0000000000000000 < Power On Reset */
#define RMU_RSTCAUSE_BODUNREGRST_XMASK 0x00000081UL /** 0000000010000001 < Brown Out Detector Unregulated Domain Reset */
#define RMU_RSTCAUSE_BODREGRST_XMASK 0x00000091UL /** 0000000010010001 < Brown Out Detector Regulated Domain Reset */
#define RMU_RSTCAUSE_EXTRST_XMASK 0x00000001UL /** 0000000000000001 < External Pin Reset */
#define RMU_RSTCAUSE_WDOGRST_XMASK 0x00000003UL /** 0000000000000011 < Watchdog Reset */
#define RMU_RSTCAUSE_LOCKUPRST_XMASK 0x0000EFDFUL /** 1110111111011111 < LOCKUP Reset */
#define RMU_RSTCAUSE_SYSREQRST_XMASK 0x0000EF9FUL /** 1110111110011111 < System Request Reset */
#define RMU_RSTCAUSE_EM4RST_XMASK 0x00000719UL /** 0000011100011001 < EM4 Reset */
#define RMU_RSTCAUSE_EM4WURST_XMASK 0x00000619UL /** 0000011000011001 < EM4 Wake-up Reset */
#define RMU_RSTCAUSE_BODAVDD0_XMASK 0x0000041FUL /** 0000010000011111 < AVDD0 Bod Reset */
#define RMU_RSTCAUSE_BODAVDD1_XMASK 0x0000021FUL /** 0000001000011111 < AVDD1 Bod Reset */
#define RMU_RSTCAUSE_BUBODVDDDREG_XMASK 0x00000001UL /** 0000000000000001 < Backup Brown Out Detector, VDD_DREG */
#define RMU_RSTCAUSE_BUBODBUVIN_XMASK 0x00000001UL /** 0000000000000001 < Backup Brown Out Detector, BU_VIN */
#define RMU_RSTCAUSE_BUBODUNREG_XMASK 0x00000001UL /** 0000000000000001 < Backup Brown Out Detector Unregulated Domain */
#define RMU_RSTCAUSE_BUBODREG_XMASK 0x00000001UL /** 0000000000000001 < Backup Brown Out Detector Regulated Domain */
#define RMU_RSTCAUSE_BUMODERST_XMASK 0x00000001UL /** 0000000000000001 < Backup mode reset */
#define NUM_RSTCAUSES 16
/* EFM32xG1, EFM32xG12, EFM32xG13 */
#elif ((_RMU_RSTCAUSE_MASK & 0x0FFFFFFF) == 0x00010F1DUL)
#define RMU_RSTCAUSE_PORST_XMASK 0x00000000UL /** 0000000000000000 < Power On Reset */
#define RMU_RSTCAUSE_BODAVDD_XMASK 0x00000001UL /** 0000000000000001 < AVDD BOD Reset */
#define RMU_RSTCAUSE_BODDVDD_XMASK 0x00000001UL /** 0000000000000001 < DVDD BOD Reset */
#define RMU_RSTCAUSE_BODREGRST_XMASK 0x00000001UL /** 0000000000000001 < Regulated Domain (DEC) BOD Reset */
#define RMU_RSTCAUSE_EXTRST_XMASK 0x00000001UL /** 0000000000000001 < External Pin Reset */
#define RMU_RSTCAUSE_LOCKUPRST_XMASK 0x0000001DUL /** 0000000000011101 < LOCKUP Reset */
#define RMU_RSTCAUSE_SYSREQRST_XMASK 0x0000001DUL /** 0000000000011101 < System Request Reset */
#define RMU_RSTCAUSE_WDOGRST_XMASK 0x0000001DUL /** 0000000000011101 < Watchdog Reset */
#define RMU_RSTCAUSE_EM4RST_XMASK 0x0000001DUL /** 0000000000011101 < EM4H/S Reset */
#define NUM_RSTCAUSES 9
/* EFM32GG11 */
#elif ((_RMU_RSTCAUSE_MASK & 0x0FFFFFFF) == 0x00011F1DUL)
#define RMU_RSTCAUSE_PORST_XMASK 0x00000000UL /** 0000000000000000 < Power On Reset */
#define RMU_RSTCAUSE_BODAVDD_XMASK 0x00000001UL /** 0000000000000001 < AVDD BOD Reset */
#define RMU_RSTCAUSE_BODDVDD_XMASK 0x00000001UL /** 0000000000000001 < DVDD BOD Reset */
#define RMU_RSTCAUSE_BODREGRST_XMASK 0x00000001UL /** 0000000000000001 < Regulated Domain (DEC) BOD Reset */
#define RMU_RSTCAUSE_EXTRST_XMASK 0x00000001UL /** 0000000000000001 < External Pin Reset */
#define RMU_RSTCAUSE_LOCKUPRST_XMASK 0x0000001DUL /** 0000000000011101 < LOCKUP Reset */
#define RMU_RSTCAUSE_SYSREQRST_XMASK 0x0000001DUL /** 0000000000011101 < System Request Reset */
#define RMU_RSTCAUSE_WDOGRST_XMASK 0x0000001DUL /** 0000000000011101 < Watchdog Reset */
#define RMU_RSTCAUSE_BUMODERST_XMASK 0x0000001DUL /** 0000000000011101 < Backup mode reset */
#define RMU_RSTCAUSE_EM4RST_XMASK 0x0000001DUL /** 0000000000011101 < EM4H/S Reset */
#define NUM_RSTCAUSES 10
#else
#error "RMU_RSTCAUSE XMASKs are not defined for this family."
#endif
/* Pin reset definitions. */
#define LB_CLW0 (*((volatile uint32_t *)(LOCKBITS_BASE) +122))
#define LB_CLW0_PINRESETSOFT (1 << 2)
#if defined(_SILICON_LABS_GECKO_INTERNAL_SDID_80)
/* Fix for errata EMU_E208 - Occasional Full Reset After Exiting EM4H. */
#define ERRATA_FIX_EMU_E208_EN
#endif
#endif /* #if defined(_RMU_RSTCAUSE_MASK) */
/*******************************************************************************
******************************* STRUCTS ***********************************
******************************************************************************/
#if defined(_RMU_RSTCAUSE_MASK)
/** Reset cause mask type for series-0 and series-1 devices. */
typedef struct {
/** Reset cause 1 bits. */
uint32_t resetCauseMask;
/** Reset cause 0 and "don't care" bits. */
uint32_t resetCauseZeroXMask;
} RMU_ResetCauseMasks_Typedef;
#endif
/*******************************************************************************
******************************* TYPEDEFS **********************************
******************************************************************************/
#if defined(_RMU_RSTCAUSE_MASK)
/** Reset cause mask table. */
static const RMU_ResetCauseMasks_Typedef resetCauseMasks[NUM_RSTCAUSES] =
{
{ RMU_RSTCAUSE_PORST, RMU_RSTCAUSE_PORST_XMASK },
#if defined(RMU_RSTCAUSE_BODUNREGRST)
{ RMU_RSTCAUSE_BODUNREGRST, RMU_RSTCAUSE_BODUNREGRST_XMASK },
#endif
#if defined(RMU_RSTCAUSE_BODREGRST)
{ RMU_RSTCAUSE_BODREGRST, RMU_RSTCAUSE_BODREGRST_XMASK },
#endif
#if defined(RMU_RSTCAUSE_AVDDBOD)
{ RMU_RSTCAUSE_AVDDBOD, RMU_RSTCAUSE_BODAVDD_XMASK },
#endif
#if defined(RMU_RSTCAUSE_DVDDBOD)
{ RMU_RSTCAUSE_DVDDBOD, RMU_RSTCAUSE_BODDVDD_XMASK },
#endif
#if defined(RMU_RSTCAUSE_DECBOD)
{ RMU_RSTCAUSE_DECBOD, RMU_RSTCAUSE_BODREGRST_XMASK },
#endif
{ RMU_RSTCAUSE_EXTRST, RMU_RSTCAUSE_EXTRST_XMASK },
{ RMU_RSTCAUSE_WDOGRST, RMU_RSTCAUSE_WDOGRST_XMASK },
{ RMU_RSTCAUSE_LOCKUPRST, RMU_RSTCAUSE_LOCKUPRST_XMASK },
{ RMU_RSTCAUSE_SYSREQRST, RMU_RSTCAUSE_SYSREQRST_XMASK },
#if defined(RMU_RSTCAUSE_EM4RST)
{ RMU_RSTCAUSE_EM4RST, RMU_RSTCAUSE_EM4RST_XMASK },
#endif
#if defined(RMU_RSTCAUSE_EM4WURST)
{ RMU_RSTCAUSE_EM4WURST, RMU_RSTCAUSE_EM4WURST_XMASK },
#endif
#if defined(RMU_RSTCAUSE_BODAVDD0)
{ RMU_RSTCAUSE_BODAVDD0, RMU_RSTCAUSE_BODAVDD0_XMASK },
#endif
#if defined(RMU_RSTCAUSE_BODAVDD1)
{ RMU_RSTCAUSE_BODAVDD1, RMU_RSTCAUSE_BODAVDD1_XMASK },
#endif
#if defined(BU_PRESENT) && defined(_SILICON_LABS_32B_SERIES_0)
{ RMU_RSTCAUSE_BUBODVDDDREG, RMU_RSTCAUSE_BUBODVDDDREG_XMASK },
{ RMU_RSTCAUSE_BUBODBUVIN, RMU_RSTCAUSE_BUBODBUVIN_XMASK },
{ RMU_RSTCAUSE_BUBODUNREG, RMU_RSTCAUSE_BUBODUNREG_XMASK },
{ RMU_RSTCAUSE_BUBODREG, RMU_RSTCAUSE_BUBODREG_XMASK },
{ RMU_RSTCAUSE_BUMODERST, RMU_RSTCAUSE_BUMODERST_XMASK },
#elif defined(RMU_RSTCAUSE_BUMODERST)
{ RMU_RSTCAUSE_BUMODERST, RMU_RSTCAUSE_BUMODERST_XMASK },
#endif
};
#endif /* #if defined(_RMU_RSTCAUSE_MASK) */
/*******************************************************************************
******************************** TEST ********************************
******************************************************************************/
#if defined(EMLIB_REGRESSION_TEST)
/* A test variable that replaces the RSTCAUSE cause register when testing
the RMU_ResetCauseGet function. */
extern uint32_t rstCause;
#else
static uint32_t rstCause = UINT32_MAX;
#endif
/** @endcond */
/*******************************************************************************
************************** GLOBAL FUNCTIONS *******************************
******************************************************************************/
/***************************************************************************//**
* @brief
* Disable/enable reset for various peripherals and signal sources.
*
* @param[in] reset Reset types to enable/disable.s
*
* @param[in] mode Reset mode.
******************************************************************************/
#if defined(__GNUC__) && __GNUC__ >= 11
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wanalyzer-shift-count-overflow"
#endif
void RMU_ResetControl(RMU_Reset_TypeDef reset, RMU_ResetMode_TypeDef mode)
{
/* Note that the RMU supports bit-band access, but not peripheral bit-field set/clear. */
#if defined(_RMU_CTRL_PINRMODE_MASK)
uint32_t val;
#endif
uint32_t shift;
shift = SL_CTZ((uint32_t)reset);
#if defined(_EMU_RSTCTRL_MASK)
BUS_RegBitWrite(&EMU->RSTCTRL, (uint32_t)shift, mode ? 1 : 0);
#elif defined(_RMU_CTRL_PINRMODE_MASK)
EFM_ASSERT(shift < 32);
val = (uint32_t)mode << shift;
RMU->CTRL = (RMU->CTRL & ~reset) | val;
#else
BUS_RegBitWrite(&RMU->CTRL, (uint32_t)shift, mode ? 1 : 0);
#endif
}
#if defined(__GNUC__) && __GNUC__ >= 11
#pragma GCC diagnostic pop
#endif
/***************************************************************************//**
* @brief
* Clear the reset cause register.
*
* @details
* This function clears all the reset cause bits of the RSTCAUSE register.
* The reset cause bits must be cleared by software before a new reset occurs.
* Otherwise, reset causes may accumulate. See @ref RMU_ResetCauseGet().
******************************************************************************/
void RMU_ResetCauseClear(void)
{
#if defined(_EMU_RSTCTRL_MASK)
EMU->CMD_SET = EMU_CMD_RSTCAUSECLR;
#else
RMU->CMD = RMU_CMD_RCCLR;
#endif
#if defined(EMU_AUXCTRL_HRCCLR)
{
uint32_t locked;
/* Clear reset causes not cleared with the RMU CMD register. */
/* (If EMU registers are locked, they must be unlocked first) */
locked = EMU->LOCK & EMU_LOCK_LOCKKEY_LOCKED;
if (locked) {
EMU_Unlock();
}
BUS_RegBitWrite(&(EMU->AUXCTRL), _EMU_AUXCTRL_HRCCLR_SHIFT, 1);
BUS_RegBitWrite(&(EMU->AUXCTRL), _EMU_AUXCTRL_HRCCLR_SHIFT, 0);
if (locked) {
EMU_Lock();
}
}
#endif
}
/***************************************************************************//**
* @brief
* Get the cause of the last reset.
*
* @details
* To be useful, the reset cause must be cleared by software before a new
* reset occurs. Otherwise, reset causes may accumulate. See @ref
* RMU_ResetCauseClear(). This function call will return the main cause for
* reset, which can be a bit mask (several causes) and clear away "noise".
*
* @return
* A reset cause mask. See the reference manual for a description
* of the reset cause mask.
******************************************************************************/
uint32_t RMU_ResetCauseGet(void)
{
#if !defined(EMLIB_REGRESSION_TEST)
if (rstCause != UINT32_MAX) {
// RMU_ResetCauseGet() has already been called since boot. Return what was already obtained.
return rstCause;
}
#endif
#if defined(_EMU_RSTCAUSE_MASK)
#if !defined(EMLIB_REGRESSION_TEST)
rstCause = EMU->RSTCAUSE;
#endif
return rstCause;
#endif
#if defined(_RMU_RSTCAUSE_MASK)
#if !defined(EMLIB_REGRESSION_TEST)
rstCause = RMU->RSTCAUSE;
#endif
uint32_t validRstCause = 0;
uint32_t zeroXMask;
uint32_t i;
for (i = 0; i < NUM_RSTCAUSES; i++) {
zeroXMask = resetCauseMasks[i].resetCauseZeroXMask;
#if defined(_SILICON_LABS_32B_SERIES_1)
/* Handle soft/hard pin reset. */
if (!(LB_CLW0 & LB_CLW0_PINRESETSOFT)) {
/* RSTCAUSE_EXTRST must be 0 if pin reset is configured as hard reset. */
switch (resetCauseMasks[i].resetCauseMask) {
case RMU_RSTCAUSE_LOCKUPRST:
/* Fallthrough */
case RMU_RSTCAUSE_SYSREQRST:
/* Fallthrough */
case RMU_RSTCAUSE_WDOGRST:
/* Fallthrough */
case RMU_RSTCAUSE_EM4RST:
zeroXMask |= RMU_RSTCAUSE_EXTRST;
break;
default:
/* MISRA requires a default case. */
break;
}
}
#endif
#if defined(_EMU_EM4CTRL_MASK) && defined(ERRATA_FIX_EMU_E208_EN)
/* Ignore BOD flags impacted by EMU_E208. */
if (*(volatile uint32_t *)(EMU_BASE + 0x88) & (0x1 << 8)) {
zeroXMask &= ~(RMU_RSTCAUSE_DECBOD
| RMU_RSTCAUSE_DVDDBOD
| RMU_RSTCAUSE_AVDDBOD);
}
#endif
/* Check reset cause requirements. Note that a bit is "don't care" if 0 in
both resetCauseMask and resetCauseZeroXMask. */
if ((rstCause & resetCauseMasks[i].resetCauseMask)
&& !(rstCause & zeroXMask)) {
/* Add this reset-cause to the mask of qualified reset-causes. */
validRstCause |= resetCauseMasks[i].resetCauseMask;
}
}
#if defined(_EMU_EM4CTRL_MASK) && defined(ERRATA_FIX_EMU_E208_EN)
/* Clear BOD flags impacted by EMU_E208. */
if (validRstCause & RMU_RSTCAUSE_EM4RST) {
validRstCause &= ~(RMU_RSTCAUSE_DECBOD
| RMU_RSTCAUSE_DVDDBOD
| RMU_RSTCAUSE_AVDDBOD);
}
#endif
#if !defined(EMLIB_REGRESSION_TEST)
// keep validRstCause in the static local variable for future calls
rstCause = validRstCause
#endif
return validRstCause;
#endif
}
/** @} (end addtogroup rmu) */
#endif /* defined(RMU_COUNT) && (RMU_COUNT > 0) */

View File

@@ -0,0 +1,433 @@
/***************************************************************************//**
* @file
* @brief System Peripheral API
*******************************************************************************
* # License
* <b>Copyright 2018 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* 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 <stddef.h>
#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 \<part_family\>_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) */

View File

@@ -0,0 +1,520 @@
/***************************************************************************//**
* @file
* @brief Timer/counter (TIMER) Peripheral API
*******************************************************************************
* # License
* <b>Copyright 2018 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* 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_timer.h"
#if defined(TIMER_COUNT) && (TIMER_COUNT > 0)
#include "sl_assert.h"
/***************************************************************************//**
* @addtogroup timer TIMER - Timer/Counter
* @brief Timer/Counter (TIMER) Peripheral API
* @details
* The timer module consists of three main parts:
* @li General timer configuration and enable control.
* @li Compare/capture control.
* @li Dead time insertion control (may not be available for all timers).
* @{
******************************************************************************/
/*******************************************************************************
************************** LOCAL FUNCTIONS ********************************
******************************************************************************/
/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
#if defined(_PRS_CONSUMER_TIMER0_CC0_MASK)
/** Map TIMER reference to index of device. */
#if defined(TIMER9)
#define TIMER_DEVICE_ID(timer) ( \
(timer) == TIMER0 ? 0 \
: (timer) == TIMER1 ? 1 \
: (timer) == TIMER2 ? 2 \
: (timer) == TIMER3 ? 3 \
: (timer) == TIMER4 ? 4 \
: (timer) == TIMER5 ? 5 \
: (timer) == TIMER6 ? 6 \
: (timer) == TIMER7 ? 7 \
: (timer) == TIMER8 ? 8 \
: (timer) == TIMER9 ? 9 \
: -1)
#elif defined(TIMER7)
#define TIMER_DEVICE_ID(timer) ( \
(timer) == TIMER0 ? 0 \
: (timer) == TIMER1 ? 1 \
: (timer) == TIMER2 ? 2 \
: (timer) == TIMER3 ? 3 \
: (timer) == TIMER4 ? 4 \
: (timer) == TIMER5 ? 5 \
: (timer) == TIMER6 ? 6 \
: (timer) == TIMER7 ? 7 \
: -1)
#elif defined(TIMER4)
#define TIMER_DEVICE_ID(timer) ( \
(timer) == TIMER0 ? 0 \
: (timer) == TIMER1 ? 1 \
: (timer) == TIMER2 ? 2 \
: (timer) == TIMER3 ? 3 \
: (timer) == TIMER4 ? 4 \
: -1)
#else
#define TIMER_DEVICE_ID(timer) ( \
(timer) == TIMER0 ? 0 \
: (timer) == TIMER1 ? 1 \
: (timer) == TIMER2 ? 2 \
: (timer) == TIMER3 ? 3 \
: -1)
#endif
#define TIMER_INPUT_CHANNEL_DTI 3UL
#define TIMER_INPUT_CHANNEL_DTIFS1 4UL
#define TIMER_INPUT_CHANNEL_DTIFS2 5UL
/**
* TIMER PRS registers are moved into the PRS register space on series 2 devices.
* The PRS Consumer registers for a timer consist of 6 registers.
*
* [0] - CC0 PRS Consumer
* [1] - CC1 PRS Consumer
* [2] - CC2 PRS Consumer
* [3] - DTI PRS Consumer
* [4] - DTIFS1 PRS Consumer
* [5] - DTIFS2 PRS Consumer
*/
typedef struct {
__IOM uint32_t CONSUMER_CH[6]; /**< TIMER PRS consumers. */
} PRS_TIMERn_Consumer_TypeDef;
typedef struct {
PRS_TIMERn_Consumer_TypeDef TIMER_CONSUMER[TIMER_COUNT];
} PRS_TIMERn_TypeDef;
/**
* @brief Configure a timer capture/compare channel to use a PRS channel as input.
*
* @param[in] timer
*
* @param[in] cc
* Timer input channel. Valid input is 0-5.
* 0 - CC0
* 1 - CC1
* 2 - CC2
* 3 - DTI
* 4 - DTIFS1
* 5 - DTIFS2
*
* @param[in] prsCh
* PRS channel number.
*
* @param[in] async
* true for asynchronous PRS channel, false for synchronous PRS channel.
*/
static void timerPrsConfig(TIMER_TypeDef * timer, unsigned int cc, unsigned int prsCh, bool async)
{
int i = TIMER_DEVICE_ID(timer);
volatile PRS_TIMERn_TypeDef * base = (PRS_TIMERn_TypeDef *) &PRS->CONSUMER_TIMER0_CC0;
EFM_ASSERT(i >= 0);
if (i >= 0) {
if (async) {
base->TIMER_CONSUMER[i].CONSUMER_CH[cc] = prsCh << _PRS_CONSUMER_TIMER0_CC0_PRSSEL_SHIFT;
} else {
base->TIMER_CONSUMER[i].CONSUMER_CH[cc] = prsCh << _PRS_CONSUMER_TIMER0_CC0_SPRSSEL_SHIFT;
}
}
}
#endif
/** @endcond */
/*******************************************************************************
************************** GLOBAL FUNCTIONS *******************************
******************************************************************************/
/***************************************************************************//**
* @brief
* Initialize TIMER.
*
* @details
* Notice that the counter top must be configured separately with, for instance
* TIMER_TopSet(). In addition, compare/capture and dead-time insertion
* initialization must be initialized separately if used, which should probably
* be done prior to using this function if configuring the TIMER to
* start when initialization is completed.
*
* @param[in] timer
* A pointer to the TIMER peripheral register block.
*
* @param[in] init
* A pointer to the TIMER initialization structure.
******************************************************************************/
void TIMER_Init(TIMER_TypeDef *timer, const TIMER_Init_TypeDef *init)
{
EFM_ASSERT(TIMER_REF_VALID(timer));
uint32_t ctrlRegVal = 0;
#if defined (_TIMER_CFG_PRESC_SHIFT)
TIMER_SyncWait(timer);
timer->EN_CLR = TIMER_EN_EN;
#if defined(_TIMER_EN_DISABLING_MASK)
while (timer->EN & _TIMER_EN_DISABLING_MASK) {
}
#endif
timer->CFG = ((uint32_t)init->prescale << _TIMER_CFG_PRESC_SHIFT)
| ((uint32_t)init->clkSel << _TIMER_CFG_CLKSEL_SHIFT)
| ((uint32_t)init->mode << _TIMER_CFG_MODE_SHIFT)
| (init->debugRun ? TIMER_CFG_DEBUGRUN : 0)
| (init->dmaClrAct ? TIMER_CFG_DMACLRACT : 0)
| (init->quadModeX4 ? TIMER_CFG_QDM_X4 : 0)
| (init->oneShot ? TIMER_CFG_OSMEN : 0)
| (init->sync ? TIMER_CFG_SYNC : 0)
| (init->disSyncOut ? TIMER_CFG_DISSYNCOUT : 0)
| (init->ati ? TIMER_CFG_ATI : 0)
| (init->rssCoist ? TIMER_CFG_RSSCOIST : 0);
timer->EN_SET = TIMER_EN_EN;
#endif
/* Stop the timer if specified to be disabled (doesn't hurt if already stopped). */
if (!(init->enable)) {
timer->CMD = TIMER_CMD_STOP;
}
/* Reset the counter. */
timer->CNT = _TIMER_CNT_RESETVALUE;
#if defined(_SILICON_LABS_32B_SERIES_0) || defined(_SILICON_LABS_32B_SERIES_1)
ctrlRegVal = ((uint32_t)init->prescale << _TIMER_CTRL_PRESC_SHIFT)
| ((uint32_t)init->clkSel << _TIMER_CTRL_CLKSEL_SHIFT)
| ((uint32_t)init->fallAction << _TIMER_CTRL_FALLA_SHIFT)
| ((uint32_t)init->riseAction << _TIMER_CTRL_RISEA_SHIFT)
| ((uint32_t)init->mode << _TIMER_CTRL_MODE_SHIFT)
| (init->debugRun ? TIMER_CTRL_DEBUGRUN : 0)
| (init->dmaClrAct ? TIMER_CTRL_DMACLRACT : 0)
| (init->quadModeX4 ? TIMER_CTRL_QDM_X4 : 0)
| (init->oneShot ? TIMER_CTRL_OSMEN : 0)
#if defined(TIMER_CTRL_DISSYNCOUT)
| (init->disSyncOut ? TIMER_CTRL_DISSYNCOUT : 0)
#endif
| (init->sync ? TIMER_CTRL_SYNC : 0);
#if defined(TIMER_CTRL_X2CNT) && defined(TIMER_CTRL_ATI) && defined(TIMER_CTRL_RSSCOIST)
ctrlRegVal |= (init->count2x ? TIMER_CTRL_X2CNT : 0)
| (init->ati ? TIMER_CTRL_ATI : 0)
| (init->rssCoist ? TIMER_CTRL_RSSCOIST : 0);
#endif
#else
ctrlRegVal = ((uint32_t)init->fallAction << _TIMER_CTRL_FALLA_SHIFT)
| ((uint32_t)init->riseAction << _TIMER_CTRL_RISEA_SHIFT)
| (init->count2x ? TIMER_CTRL_X2CNT : 0);
#endif
timer->CTRL = ctrlRegVal;
/* Start the timer if specified to be enabled (doesn't hurt if already started). */
if (init->enable) {
timer->CMD = TIMER_CMD_START;
}
}
/***************************************************************************//**
* @brief
* Initialize the TIMER compare/capture channel.
*
* @details
* Notice that if operating the channel in compare mode, the CCV and CCVB register
* must be set separately, as required.
*
* @param[in] timer
* A pointer to the TIMER peripheral register block.
*
* @param[in] ch
* A compare/capture channel to initialize for.
*
* @param[in] init
* A pointer to the TIMER initialization structure.
******************************************************************************/
void TIMER_InitCC(TIMER_TypeDef *timer,
unsigned int ch,
const TIMER_InitCC_TypeDef *init)
{
EFM_ASSERT(TIMER_REF_VALID(timer));
EFM_ASSERT(TIMER_REF_CH_VALIDATE(timer, ch));
#if defined (_TIMER_CC_CFG_MASK)
TIMER_SyncWait(timer);
timer->EN_CLR = TIMER_EN_EN;
#if defined(_TIMER_EN_DISABLING_MASK)
while (timer->EN & _TIMER_EN_DISABLING_MASK) {
}
#endif
timer->CC[ch].CFG =
((uint32_t)init->mode << _TIMER_CC_CFG_MODE_SHIFT)
| (init->filter ? TIMER_CC_CFG_FILT_ENABLE : 0)
| (init->coist ? TIMER_CC_CFG_COIST : 0)
| ((uint32_t)init->prsOutput << _TIMER_CC_CFG_PRSCONF_SHIFT);
if (init->prsInput) {
timer->CC[ch].CFG |= (uint32_t)init->prsInputType << _TIMER_CC_CFG_INSEL_SHIFT;
bool async = (init->prsInputType != timerPrsInputSync);
timerPrsConfig(timer, ch, init->prsSel, async);
} else {
timer->CC[ch].CFG |= TIMER_CC_CFG_INSEL_PIN;
}
timer->EN_SET = TIMER_EN_EN;
timer->CC[ch].CTRL =
((uint32_t)init->eventCtrl << _TIMER_CC_CTRL_ICEVCTRL_SHIFT)
| ((uint32_t)init->edge << _TIMER_CC_CTRL_ICEDGE_SHIFT)
| ((uint32_t)init->cufoa << _TIMER_CC_CTRL_CUFOA_SHIFT)
| ((uint32_t)init->cofoa << _TIMER_CC_CTRL_COFOA_SHIFT)
| ((uint32_t)init->cmoa << _TIMER_CC_CTRL_CMOA_SHIFT)
| (init->outInvert ? TIMER_CC_CTRL_OUTINV : 0);
#else
timer->CC[ch].CTRL =
((uint32_t)init->eventCtrl << _TIMER_CC_CTRL_ICEVCTRL_SHIFT)
| ((uint32_t)init->edge << _TIMER_CC_CTRL_ICEDGE_SHIFT)
| ((uint32_t)init->prsSel << _TIMER_CC_CTRL_PRSSEL_SHIFT)
| ((uint32_t)init->cufoa << _TIMER_CC_CTRL_CUFOA_SHIFT)
| ((uint32_t)init->cofoa << _TIMER_CC_CTRL_COFOA_SHIFT)
| ((uint32_t)init->cmoa << _TIMER_CC_CTRL_CMOA_SHIFT)
| ((uint32_t)init->mode << _TIMER_CC_CTRL_MODE_SHIFT)
| (init->filter ? TIMER_CC_CTRL_FILT_ENABLE : 0)
| (init->prsInput ? TIMER_CC_CTRL_INSEL_PRS : 0)
| (init->coist ? TIMER_CC_CTRL_COIST : 0)
| (init->outInvert ? TIMER_CC_CTRL_OUTINV : 0)
#if defined(_TIMER_CC_CTRL_PRSCONF_MASK)
| ((uint32_t)init->prsOutput << _TIMER_CC_CTRL_PRSCONF_SHIFT)
#endif
;
#endif
}
#if defined(_TIMER_DTCTRL_MASK)
/***************************************************************************//**
* @brief
* Initialize the TIMER DTI unit.
*
* @param[in] timer
* A pointer to the TIMER peripheral register block.
*
* @param[in] init
* A pointer to the TIMER DTI initialization structure.
******************************************************************************/
void TIMER_InitDTI(TIMER_TypeDef *timer, const TIMER_InitDTI_TypeDef *init)
{
EFM_ASSERT(TIMER_SupportsDTI(timer));
/* Make sure the DTI unit is disabled while initializing. */
TIMER_EnableDTI(timer, false);
#if defined (_TIMER_DTCFG_MASK)
TIMER_SyncWait(timer);
timer->EN_CLR = TIMER_EN_EN;
#if defined(_TIMER_EN_DISABLING_MASK)
while (timer->EN & _TIMER_EN_DISABLING_MASK) {
}
#endif
timer->DTCFG = (init->autoRestart ? TIMER_DTCFG_DTDAS : 0)
| (init->enablePrsSource ? TIMER_DTCFG_DTPRSEN : 0);
if (init->enablePrsSource) {
timerPrsConfig(timer, TIMER_INPUT_CHANNEL_DTI, init->prsSel, true);
}
timer->DTTIMECFG =
((uint32_t)init->prescale << _TIMER_DTTIMECFG_DTPRESC_SHIFT)
| ((uint32_t)init->riseTime << _TIMER_DTTIMECFG_DTRISET_SHIFT)
| ((uint32_t)init->fallTime << _TIMER_DTTIMECFG_DTFALLT_SHIFT);
timer->DTFCFG =
(init->enableFaultSourceCoreLockup ? TIMER_DTFCFG_DTLOCKUPFEN : 0)
| (init->enableFaultSourceDebugger ? TIMER_DTFCFG_DTDBGFEN : 0)
| (init->enableFaultSourcePrsSel0 ? TIMER_DTFCFG_DTPRS0FEN : 0)
| (init->enableFaultSourcePrsSel1 ? TIMER_DTFCFG_DTPRS1FEN : 0)
| ((uint32_t)(init->faultAction) << _TIMER_DTFCFG_DTFA_SHIFT);
if (init->enableFaultSourcePrsSel0) {
timerPrsConfig(timer, TIMER_INPUT_CHANNEL_DTIFS1, init->faultSourcePrsSel0, true);
}
if (init->enableFaultSourcePrsSel1) {
timerPrsConfig(timer, TIMER_INPUT_CHANNEL_DTIFS2, init->faultSourcePrsSel1, true);
}
timer->EN_SET = TIMER_EN_EN;
#endif
#if defined(TIMER_DTCTRL_DTDAS)
/* Set up the DTCTRL register.
The enable bit will be set at the end of the function if specified. */
timer->DTCTRL =
(init->autoRestart ? TIMER_DTCTRL_DTDAS : 0)
| (init->activeLowOut ? TIMER_DTCTRL_DTIPOL : 0)
| (init->invertComplementaryOut ? TIMER_DTCTRL_DTCINV : 0)
| (init->enablePrsSource ? TIMER_DTCTRL_DTPRSEN : 0)
| ((uint32_t)(init->prsSel) << _TIMER_DTCTRL_DTPRSSEL_SHIFT);
#endif
#if defined (TIMER_DTCFG_DTDAS)
timer->DTCTRL = (init->activeLowOut ? TIMER_DTCTRL_DTIPOL : 0)
| (init->invertComplementaryOut ? TIMER_DTCTRL_DTCINV : 0);
#endif
#if defined (_TIMER_DTTIME_DTPRESC_SHIFT)
/* Set up the DTTIME register. */
timer->DTTIME = ((uint32_t)init->prescale << _TIMER_DTTIME_DTPRESC_SHIFT)
| ((uint32_t)init->riseTime << _TIMER_DTTIME_DTRISET_SHIFT)
| ((uint32_t)init->fallTime << _TIMER_DTTIME_DTFALLT_SHIFT);
#endif
#if defined (TIMER_DTFC_DTLOCKUPFEN)
/* Set up the DTFC register. */
timer->DTFC =
(init->enableFaultSourceCoreLockup ? TIMER_DTFC_DTLOCKUPFEN : 0)
| (init->enableFaultSourceDebugger ? TIMER_DTFC_DTDBGFEN : 0)
| (init->enableFaultSourcePrsSel0 ? TIMER_DTFC_DTPRS0FEN : 0)
| (init->enableFaultSourcePrsSel1 ? TIMER_DTFC_DTPRS1FEN : 0)
| ((uint32_t)init->faultAction << _TIMER_DTFC_DTFA_SHIFT)
| ((uint32_t)init->faultSourcePrsSel0 << _TIMER_DTFC_DTPRS0FSEL_SHIFT)
| ((uint32_t)init->faultSourcePrsSel1 << _TIMER_DTFC_DTPRS1FSEL_SHIFT);
#endif
/* Set up the DTOGEN register. */
timer->DTOGEN = init->outputsEnableMask;
/* Clear any previous DTI faults. */
TIMER_ClearDTIFault(timer, TIMER_GetDTIFault(timer));
/* Enable/disable before returning. */
TIMER_EnableDTI(timer, init->enable);
}
#endif
/***************************************************************************//**
* @brief
* Reset the TIMER to the same state that it was in after a hardware reset.
*
* @note
* The ROUTE register is NOT reset by this function to allow for
* a centralized setup of this feature.
*
* @param[in] timer
* A pointer to the TIMER peripheral register block.
******************************************************************************/
void TIMER_Reset(TIMER_TypeDef *timer)
{
int i;
EFM_ASSERT(TIMER_REF_VALID(timer));
#if defined(TIMER_EN_EN)
timer->EN_SET = TIMER_EN_EN;
#endif
/* Make sure disabled first, before resetting other registers. */
timer->CMD = TIMER_CMD_STOP;
timer->CTRL = _TIMER_CTRL_RESETVALUE;
timer->IEN = _TIMER_IEN_RESETVALUE;
#if defined (TIMER_HAS_SET_CLEAR)
timer->IF_CLR = _TIMER_IF_MASK;
#else
timer->IFC = _TIMER_IFC_MASK;
#endif
timer->TOPB = _TIMER_TOPB_RESETVALUE;
/* Write TOP after TOPB to invalidate TOPB (clear TIMER_STATUS_TOPBV). */
timer->TOP = _TIMER_TOP_RESETVALUE;
timer->CNT = _TIMER_CNT_RESETVALUE;
/* Do not reset the route register, setting should be done independently. */
/* Note: The ROUTE register may be locked by the DTLOCK register. */
for (i = 0; TIMER_REF_CH_VALIDATE(timer, i); i++) {
timer->CC[i].CTRL = _TIMER_CC_CTRL_RESETVALUE;
#if defined (_TIMER_CC_CCV_RESETVALUE) && defined (_TIMER_CC_CCVB_RESETVALUE)
timer->CC[i].CCV = _TIMER_CC_CCV_RESETVALUE;
timer->CC[i].CCVB = _TIMER_CC_CCVB_RESETVALUE;
#endif
#if defined (_TIMER_CC_OC_RESETVALUE) && defined (_TIMER_CC_OCB_RESETVALUE) \
&& defined (_TIMER_CC_ICF_RESETVALUE) && defined (_TIMER_CC_ICOF_RESETVALUE)
timer->CC[i].OC = _TIMER_CC_OC_RESETVALUE;
timer->CC[i].OCB = _TIMER_CC_OCB_RESETVALUE;
#endif
}
/* Reset dead time insertion module, which has no effect on timers without DTI. */
#if defined(_TIMER_DTCFG_MASK)
timer->DTLOCK = TIMER_DTLOCK_DTILOCKKEY_UNLOCK;
timer->DTCTRL = _TIMER_DTCTRL_RESETVALUE;
timer->DTOGEN = _TIMER_DTOGEN_RESETVALUE;
timer->DTFAULTC = _TIMER_DTFAULTC_MASK;
#elif defined(TIMER_DTLOCK_LOCKKEY_UNLOCK)
/* Unlock DTI registers first if locked. */
timer->DTLOCK = TIMER_DTLOCK_LOCKKEY_UNLOCK;
timer->DTCTRL = _TIMER_DTCTRL_RESETVALUE;
timer->DTTIME = _TIMER_DTTIME_RESETVALUE;
timer->DTFC = _TIMER_DTFC_RESETVALUE;
timer->DTOGEN = _TIMER_DTOGEN_RESETVALUE;
timer->DTFAULTC = _TIMER_DTFAULTC_MASK;
#endif
#if defined(_TIMER_CFG_MASK)
TIMER_SyncWait(timer);
/* CFG registers must be reset after the timer is disabled */
timer->EN_CLR = TIMER_EN_EN;
#if defined(_TIMER_EN_DISABLING_MASK)
while (timer->EN & _TIMER_EN_DISABLING_MASK) {
}
#endif
timer->CFG = _TIMER_CFG_RESETVALUE;
for (i = 0; TIMER_REF_CH_VALIDATE(timer, i); i++) {
timer->CC[i].CFG = _TIMER_CC_CFG_RESETVALUE;
}
timer->DTCFG = _TIMER_DTCFG_RESETVALUE;
timer->DTFCFG = _TIMER_DTFCFG_RESETVALUE;
timer->DTTIMECFG = _TIMER_DTTIMECFG_RESETVALUE;
#endif
}
#if defined(TIMER_STATUS_SYNCBUSY)
/**
* @brief Wait for pending synchronization to finish
*
* @param[in] timer
*/
void TIMER_SyncWait(TIMER_TypeDef * timer)
{
while (((timer->EN & TIMER_EN_EN) != 0U)
&& ((timer->STATUS & TIMER_STATUS_SYNCBUSY) != 0U)) {
/* Wait for synchronization to complete */
}
}
#endif
/** @} (end addtogroup timer) */
#endif /* defined(TIMER_COUNT) && (TIMER_COUNT > 0) */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,636 @@
/***************************************************************************//**
* @file
* @brief Digital to Analog Converter (VDAC) Peripheral API
*******************************************************************************
* # License
* <b>Copyright 2018 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* 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_vdac.h"
#if defined(VDAC_COUNT) && (VDAC_COUNT > 0)
#include "em_cmu.h"
/***************************************************************************//**
* @addtogroup vdac
* @{
******************************************************************************/
/*******************************************************************************
******************************* DEFINES ***********************************
******************************************************************************/
/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
/** Validation of the VDAC channel for assert statements. */
#define VDAC_CH_VALID(ch) ((ch) <= 1)
/** A maximum VDAC clock. */
#define VDAC_MAX_CLOCK 1000000
/** The maximum clock frequency of the internal clock oscillator, 10 MHz + 20%. */
#define VDAC_INTERNAL_CLOCK_FREQ 12000000
/** @endcond */
/*******************************************************************************
*************************** LOCAL FUNCTIONS *******************************
******************************************************************************/
/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
#if defined(_VDAC_EN_MASK)
static void VDAC_DisableModule(VDAC_TypeDef* vdac)
{
while (vdac->STATUS & VDAC_STATUS_SYNCBUSY) {
}
/* Wait for all synchronizations to finish */
if (vdac->EN & VDAC_EN_EN) {
vdac->CMD = _VDAC_CMD_CH0DIS_MASK;
while (vdac->STATUS & (VDAC_STATUS_CH0ENS)) {
}
vdac->CMD = _VDAC_CMD_CH1DIS_MASK;
while (vdac->STATUS & (VDAC_STATUS_CH1ENS)) {
}
#if defined(_VDAC_CMD_CH0FIFOFLUSH_MASK)
while (vdac->STATUS & VDAC_STATUS_SYNCBUSY) {
}
vdac->CMD = VDAC_CMD_CH0FIFOFLUSH | VDAC_CMD_CH1FIFOFLUSH;
while (vdac->STATUS & (VDAC_STATUS_SYNCBUSY | VDAC_STATUS_CH0FIFOFLBUSY | VDAC_STATUS_CH1FIFOFLBUSY)) {
}
#endif
vdac->EN_CLR = _VDAC_EN_EN_MASK;
while (vdac->EN & _VDAC_EN_DISABLING_MASK) {
}
}
}
#endif
/** @endcond */
/*******************************************************************************
************************** GLOBAL FUNCTIONS *******************************
******************************************************************************/
/***************************************************************************//**
* @brief
* Enable/disable the VDAC channel.
*
* @param[in] vdac
* A pointer to the VDAC peripheral register block.
*
* @param[in] ch
* A channel to enable/disable.
*
* @param[in] enable
* True to enable VDAC channel, false to disable.
******************************************************************************/
void VDAC_Enable(VDAC_TypeDef *vdac, unsigned int ch, bool enable)
{
EFM_ASSERT(VDAC_REF_VALID(vdac));
EFM_ASSERT(VDAC_CH_VALID(ch));
#if defined(_VDAC_STATUS_SYNCBUSY_MASK)
while (vdac->STATUS & VDAC_STATUS_SYNCBUSY) {
}
#endif
if (ch == 0) {
if (enable) {
vdac->CMD = VDAC_CMD_CH0EN;
while ((vdac->STATUS & VDAC_STATUS_CH0ENS) == 0) {
}
} else {
vdac->CMD = VDAC_CMD_CH0DIS;
while (vdac->STATUS & VDAC_STATUS_CH0ENS) {
}
#if defined(_VDAC_CMD_CH0FIFOFLUSH_MASK)
while (vdac->STATUS & VDAC_STATUS_SYNCBUSY) {
}
vdac->CMD = VDAC_CMD_CH0FIFOFLUSH;
while (vdac->STATUS & VDAC_STATUS_CH0FIFOFLBUSY) {
}
#endif
}
} else {
if (enable) {
vdac->CMD = VDAC_CMD_CH1EN;
while ((vdac->STATUS & VDAC_STATUS_CH1ENS) == 0) {
}
} else {
vdac->CMD = VDAC_CMD_CH1DIS;
while (vdac->STATUS & VDAC_STATUS_CH1ENS) {
}
#if defined(_VDAC_CMD_CH1FIFOFLUSH_MASK)
while (vdac->STATUS & VDAC_STATUS_SYNCBUSY) {
}
vdac->CMD = VDAC_CMD_CH1FIFOFLUSH;
while (vdac->STATUS & VDAC_STATUS_CH1FIFOFLBUSY) {
}
#endif
}
}
}
/***************************************************************************//**
* @brief
* Initialize VDAC.
*
* @details
* Initializes the common parts for both channels. This function will also load
* calibration values from the Device Information (DI) page into the VDAC
* calibration register.
* To complete a VDAC setup, channel control configuration must also be done.
* See VDAC_InitChannel().
*
* @note
* This function will disable both channels prior to configuration.
*
* @param[in] vdac
* A pointer to the VDAC peripheral register block.
*
* @param[in] init
* A pointer to the VDAC initialization structure.
******************************************************************************/
void VDAC_Init(VDAC_TypeDef *vdac, const VDAC_Init_TypeDef *init)
{
EFM_ASSERT(VDAC_REF_VALID(vdac));
uint32_t config = 0;
#if defined(_SILICON_LABS_32B_SERIES_0) || defined(_SILICON_LABS_32B_SERIES_1)
uint32_t cal;
uint32_t const volatile *calData;
/* Make sure both channels are disabled. */
vdac->CMD = VDAC_CMD_CH0DIS | VDAC_CMD_CH1DIS;
while (vdac->STATUS & (VDAC_STATUS_CH0ENS | VDAC_STATUS_CH1ENS)) {
}
/* Get the OFFSETTRIM calibration value. */
cal = ((DEVINFO->VDAC0CH1CAL & _DEVINFO_VDAC0CH1CAL_OFFSETTRIM_MASK)
>> _DEVINFO_VDAC0CH1CAL_OFFSETTRIM_SHIFT)
<< _VDAC_CAL_OFFSETTRIM_SHIFT;
if (init->mainCalibration) {
calData = &DEVINFO->VDAC0MAINCAL;
} else {
calData = &DEVINFO->VDAC0ALTCAL;
}
/* Get the correct GAINERRTRIM calibration value. */
switch (init->reference) {
case vdacRef1V25Ln:
config = (*calData & _DEVINFO_VDAC0MAINCAL_GAINERRTRIM1V25LN_MASK)
>> _DEVINFO_VDAC0MAINCAL_GAINERRTRIM1V25LN_SHIFT;
break;
case vdacRef2V5Ln:
config = (*calData & _DEVINFO_VDAC0MAINCAL_GAINERRTRIM2V5LN_MASK)
>> _DEVINFO_VDAC0MAINCAL_GAINERRTRIM2V5LN_SHIFT;
break;
case vdacRef1V25:
config = (*calData & _DEVINFO_VDAC0MAINCAL_GAINERRTRIM1V25_MASK)
>> _DEVINFO_VDAC0MAINCAL_GAINERRTRIM1V25_SHIFT;
break;
case vdacRef2V5:
config = (*calData & _DEVINFO_VDAC0MAINCAL_GAINERRTRIM2V5_MASK)
>> _DEVINFO_VDAC0MAINCAL_GAINERRTRIM2V5_SHIFT;
break;
case vdacRefAvdd:
case vdacRefExtPin:
config = (*calData & _DEVINFO_VDAC0MAINCAL_GAINERRTRIMVDDANAEXTPIN_MASK)
>> _DEVINFO_VDAC0MAINCAL_GAINERRTRIMVDDANAEXTPIN_SHIFT;
break;
}
/* Set the sGAINERRTRIM calibration value. */
cal |= config << _VDAC_CAL_GAINERRTRIM_SHIFT;
/* Get the GAINERRTRIMCH1 calibration value. */
switch (init->reference) {
case vdacRef1V25Ln:
case vdacRef1V25:
case vdacRefAvdd:
case vdacRefExtPin:
config = (DEVINFO->VDAC0CH1CAL & _DEVINFO_VDAC0CH1CAL_GAINERRTRIMCH1A_MASK)
>> _DEVINFO_VDAC0CH1CAL_GAINERRTRIMCH1A_SHIFT;
break;
case vdacRef2V5Ln:
case vdacRef2V5:
config = (DEVINFO->VDAC0CH1CAL & _DEVINFO_VDAC0CH1CAL_GAINERRTRIMCH1B_MASK)
>> _DEVINFO_VDAC0CH1CAL_GAINERRTRIMCH1B_SHIFT;
break;
}
/* Set the GAINERRTRIM calibration value. */
cal |= config << _VDAC_CAL_GAINERRTRIMCH1_SHIFT;
config = ((uint32_t)init->asyncClockMode << _VDAC_CTRL_DACCLKMODE_SHIFT)
| ((uint32_t)init->warmupKeepOn << _VDAC_CTRL_WARMUPMODE_SHIFT)
| ((uint32_t)init->refresh << _VDAC_CTRL_REFRESHPERIOD_SHIFT)
| (((uint32_t)init->prescaler << _VDAC_CTRL_PRESC_SHIFT)
& _VDAC_CTRL_PRESC_MASK)
| ((uint32_t)init->reference << _VDAC_CTRL_REFSEL_SHIFT)
| ((uint32_t)init->ch0ResetPre << _VDAC_CTRL_CH0PRESCRST_SHIFT)
| ((uint32_t)init->outEnablePRS << _VDAC_CTRL_OUTENPRS_SHIFT)
| ((uint32_t)init->sineEnable << _VDAC_CTRL_SINEMODE_SHIFT)
| ((uint32_t)init->diff << _VDAC_CTRL_DIFF_SHIFT);
/* Write to VDAC registers. */
vdac->CAL = cal;
vdac->CTRL = config;
#elif defined(_SILICON_LABS_32B_SERIES_2)
VDAC_DisableModule(vdac);
config = (
#if defined(VDAC_CFG_SINEMODEPRS)
((uint32_t)init->sineModePrsEnable ? VDAC_CFG_SINEMODEPRS : 0U) |
#endif
#if defined(VDAC_CFG_OUTENPRS)
((uint32_t)init->prsOutEnable ? VDAC_CFG_OUTENPRS : 0U) |
#endif
(((uint32_t)init->warmupTime << _VDAC_CFG_WARMUPTIME_SHIFT) & _VDAC_CFG_WARMUPTIME_MASK)
| ((uint32_t)init->dbgHalt << _VDAC_CFG_DBGHALT_SHIFT)
| ((uint32_t)init->onDemandClk << _VDAC_CFG_ONDEMANDCLK_SHIFT)
| ((uint32_t)init->dmaWakeUp << _VDAC_CFG_DMAWU_SHIFT)
| ((uint32_t)init->biasKeepWarm << _VDAC_CFG_BIASKEEPWARM_SHIFT)
| ((uint32_t)init->refresh << _VDAC_CFG_REFRESHPERIOD_SHIFT)
| ((uint32_t)init->timerOverflow << _VDAC_CFG_TIMEROVRFLOWPERIOD_SHIFT)
| (((uint32_t)init->prescaler << _VDAC_CFG_PRESC_SHIFT) & _VDAC_CFG_PRESC_MASK)
| ((uint32_t)init->reference << _VDAC_CFG_REFRSEL_SHIFT)
| ((uint32_t)init->ch0ResetPre << _VDAC_CFG_CH0PRESCRST_SHIFT)
| ((uint32_t)init->sineReset << _VDAC_CFG_SINERESET_SHIFT)
| ((uint32_t)init->sineEnable << _VDAC_CFG_SINEMODE_SHIFT)
| ((uint32_t)init->diff << _VDAC_CFG_DIFF_SHIFT));
vdac->CFG = config;
#endif
}
/***************************************************************************//**
* @brief
* Initialize a VDAC channel.
*
* @param[in] vdac
* A pointer to the VDAC peripheral register block.
*
* @param[in] init
* A pointer to the VDAC channel initialization structure.
*
* @param[in] ch
* A channel number to initialize.
******************************************************************************/
void VDAC_InitChannel(VDAC_TypeDef *vdac,
const VDAC_InitChannel_TypeDef *init,
unsigned int ch)
{
uint32_t channelConfig, vdacStatus;
EFM_ASSERT(VDAC_REF_VALID(vdac));
EFM_ASSERT(VDAC_CH_VALID(ch));
vdacStatus = vdac->STATUS;
#if defined(_SILICON_LABS_32B_SERIES_0) || defined(_SILICON_LABS_32B_SERIES_1)
/* Make sure both channels are disabled. */
vdac->CMD = VDAC_CMD_CH0DIS | VDAC_CMD_CH1DIS;
while (vdac->STATUS & (VDAC_STATUS_CH0ENS | VDAC_STATUS_CH1ENS)) {
}
channelConfig = ((uint32_t)init->prsSel << _VDAC_CH0CTRL_PRSSEL_SHIFT)
| ((uint32_t)init->prsAsync << _VDAC_CH0CTRL_PRSASYNC_SHIFT)
| ((uint32_t)init->trigMode << _VDAC_CH0CTRL_TRIGMODE_SHIFT)
| ((uint32_t)init->sampleOffMode << _VDAC_CH0CTRL_CONVMODE_SHIFT);
if (ch == 0) {
vdac->CH0CTRL = channelConfig;
} else {
vdac->CH1CTRL = channelConfig;
}
#elif defined(_SILICON_LABS_32B_SERIES_2)
VDAC_DisableModule(vdac);
channelConfig = ((uint32_t)init->warmupKeepOn << _VDAC_CH0CFG_KEEPWARM_SHIFT)
| ((uint32_t)init->highCapLoadEnable << _VDAC_CH0CFG_HIGHCAPLOADEN_SHIFT)
| (((uint32_t)init->fifoLowDataThreshold << _VDAC_CH0CFG_FIFODVL_SHIFT) & _VDAC_CH0CFG_FIFODVL_MASK)
| ((uint32_t)init->chRefreshSource << _VDAC_CH0CFG_REFRESHSOURCE_SHIFT)
| ((uint32_t)init->trigMode << _VDAC_CH0CFG_TRIGMODE_SHIFT)
| ((uint32_t)init->powerMode << _VDAC_CH0CFG_POWERMODE_SHIFT)
| ((uint32_t)init->sampleOffMode << _VDAC_CH0CFG_CONVMODE_SHIFT);
if (ch == 0) {
vdac->CH0CFG = channelConfig;
vdac->OUTTIMERCFG = ((uint32_t)(vdac->OUTTIMERCFG & ~(_VDAC_OUTTIMERCFG_CH0OUTHOLDTIME_MASK)))
| (((uint32_t)init->holdOutTime << _VDAC_OUTTIMERCFG_CH0OUTHOLDTIME_SHIFT) & _VDAC_OUTTIMERCFG_CH0OUTHOLDTIME_MASK);
vdac->EN_SET = _VDAC_EN_EN_MASK;
vdac->OUTCTRL = ((uint32_t)(vdac->OUTCTRL & ~(_VDAC_OUTCTRL_ABUSPINSELCH0_MASK | _VDAC_OUTCTRL_ABUSPORTSELCH0_MASK | _VDAC_OUTCTRL_SHORTCH0_MASK | _VDAC_OUTCTRL_AUXOUTENCH0_MASK | _VDAC_OUTCTRL_MAINOUTENCH0_MASK)))
| (((uint32_t)init->pin << _VDAC_OUTCTRL_ABUSPINSELCH0_SHIFT) & _VDAC_OUTCTRL_ABUSPINSELCH0_MASK)
| ((uint32_t)init->port << _VDAC_OUTCTRL_ABUSPORTSELCH0_SHIFT)
| ((uint32_t)init->shortOutput << _VDAC_OUTCTRL_SHORTCH0_SHIFT)
| ((uint32_t)init->auxOutEnable << _VDAC_OUTCTRL_AUXOUTENCH0_SHIFT)
| ((uint32_t)init->mainOutEnable << _VDAC_OUTCTRL_MAINOUTENCH0_SHIFT);
} else if (ch == 1) {
vdac->CH1CFG = channelConfig;
vdac->OUTTIMERCFG = (vdac->OUTTIMERCFG & ~(_VDAC_OUTTIMERCFG_CH1OUTHOLDTIME_MASK))
| (((uint32_t)init->holdOutTime << _VDAC_OUTTIMERCFG_CH1OUTHOLDTIME_SHIFT) & _VDAC_OUTTIMERCFG_CH1OUTHOLDTIME_MASK);
vdac->EN_SET = _VDAC_EN_EN_MASK;
vdac->OUTCTRL = ((uint32_t)(vdac->OUTCTRL & ~(_VDAC_OUTCTRL_ABUSPINSELCH1_MASK | _VDAC_OUTCTRL_ABUSPORTSELCH1_MASK | _VDAC_OUTCTRL_SHORTCH1_MASK | _VDAC_OUTCTRL_AUXOUTENCH1_MASK | _VDAC_OUTCTRL_MAINOUTENCH1_MASK)))
| (((uint32_t)init->pin << _VDAC_OUTCTRL_ABUSPINSELCH1_SHIFT) & _VDAC_OUTCTRL_ABUSPINSELCH1_MASK)
| ((uint32_t)init->port << _VDAC_OUTCTRL_ABUSPORTSELCH1_SHIFT)
| ((uint32_t)init->shortOutput << _VDAC_OUTCTRL_SHORTCH1_SHIFT)
| ((uint32_t)init->auxOutEnable << _VDAC_OUTCTRL_AUXOUTENCH1_SHIFT)
| ((uint32_t)init->mainOutEnable << _VDAC_OUTCTRL_MAINOUTENCH1_SHIFT);
}
#endif
/* Check if the channel must be enabled. */
if (init->enable) {
if (ch == 0) {
vdac->CMD = VDAC_CMD_CH0EN;
} else {
vdac->CMD = VDAC_CMD_CH1EN;
}
}
/* Check if the other channel had to be turned off above
* and needs to be turned on again. */
if (ch == 0) {
if (vdacStatus & VDAC_STATUS_CH1ENS) {
vdac->CMD = VDAC_CMD_CH1EN;
}
} else {
if (vdacStatus & VDAC_STATUS_CH0ENS) {
vdac->CMD = VDAC_CMD_CH0EN;
}
}
}
/***************************************************************************//**
* @brief
* Set the output signal of a VDAC channel to a given value.
*
* @details
* This function sets the output signal of a VDAC channel by writing @p value
* to the corresponding CHnDATA register.
*
* @param[in] vdac
* A pointer to the VDAC peripheral register block.
*
* @param[in] channel
* A channel number to set the output of.
*
* @param[in] value
* A value to write to the channel output register CHnDATA.
******************************************************************************/
void VDAC_ChannelOutputSet(VDAC_TypeDef *vdac,
unsigned int channel,
uint32_t value)
{
switch (channel) {
case 0:
VDAC_Channel0OutputSet(vdac, value);
break;
case 1:
VDAC_Channel1OutputSet(vdac, value);
break;
default:
EFM_ASSERT(0);
break;
}
}
#if defined(_SILICON_LABS_32B_SERIES_0) || defined(_SILICON_LABS_32B_SERIES_1)
/***************************************************************************//**
* @brief
* Calculate the prescaler value used to determine VDAC clock.
*
* @details
* The VDAC clock is given by the input clock divided by the prescaler+1.
*
* VDAC_CLK = IN_CLK / (prescale + 1)
*
* The maximum VDAC clock is 1 MHz. The input clock is HFPERCLK/HFPERCCLK
* when VDAC synchronous mode is selected, or an internal oscillator of
* 10 MHz +/- 20% when asynchronous mode is selected.
*
* @note
* If the requested VDAC frequency is low and the maximum prescaler value can't
* adjust the actual VDAC frequency lower than requested, the maximum prescaler
* value is returned resulting in a higher VDAC frequency than requested.
*
* @param[in] vdacFreq VDAC frequency target. The frequency will automatically
* be adjusted to be below maximum allowed VDAC clock.
*
* @param[in] syncMode Set to true if you intend to use VDAC in synchronous
* mode.
*
* @param[in] hfperFreq Frequency in Hz of HFPERCLK/HFPERCCLK oscillator.
* Set to 0 to use the currently defined HFPERCLK/HFPERCCLK clock setting.
* This parameter is only used when syncMode is set to true.
*
* @return
* A prescaler value to use for VDAC to achieve a clock value less than
* or equal to @p vdacFreq.
******************************************************************************/
uint32_t VDAC_PrescaleCalc(uint32_t vdacFreq, bool syncMode, uint32_t hfperFreq)
{
uint32_t ret, refFreq;
/* Make sure that the selected VDAC clock is below the maximum value. */
if (vdacFreq > VDAC_MAX_CLOCK) {
vdacFreq = VDAC_MAX_CLOCK;
}
if (!syncMode) {
refFreq = VDAC_INTERNAL_CLOCK_FREQ;
} else {
if (hfperFreq) {
refFreq = hfperFreq;
} else {
refFreq = CMU_ClockFreqGet(cmuClock_VDAC0);
}
}
/* Iterate to determine the best prescaler value. Start with the lowest */
/* prescaler value to get the first equal or less VDAC */
/* frequency value. */
for (ret = 0; ret <= (_VDAC_CTRL_PRESC_MASK >> _VDAC_CTRL_PRESC_SHIFT); ret++) {
if ((refFreq / (ret + 1)) <= vdacFreq) {
break;
}
}
/* If ret is higher than the maximum prescaler value, make sure to return
the maximum value. */
if (ret > (_VDAC_CTRL_PRESC_MASK >> _VDAC_CTRL_PRESC_SHIFT)) {
ret = _VDAC_CTRL_PRESC_MASK >> _VDAC_CTRL_PRESC_SHIFT;
}
return ret;
}
#else
/***************************************************************************//**
* @brief
* Calculate the prescaler value used to determine VDAC clock.
*
* @details
* The VDAC clock is given by the input clock divided by the prescaler+1.
*
* VDAC_CLK = IN_CLK / (prescale + 1)
*
* The maximum VDAC clock is 1 MHz.
*
* @note
* If the requested VDAC frequency is low and the maximum prescaler value can't
* adjust the actual VDAC frequency lower than requested, the maximum prescaler
* value is returned resulting in a higher VDAC frequency than requested.
*
* @param[in] vdac
* Pointer to VDAC peripheral register block.
*
* @param[in] vdacFreq VDAC frequency target. The frequency will automatically
* be adjusted to be below maximum allowed VDAC clock.
*
* @return
* A prescaler value to use for VDAC to achieve a clock value less than
* or equal to @p vdacFreq.
******************************************************************************/
uint32_t VDAC_PrescaleCalc(VDAC_TypeDef *vdac, uint32_t vdacFreq)
{
uint32_t ret = 0;
uint32_t refFreq = 0;
/* Make sure that the selected VDAC clock is below the maximum value. */
if (vdacFreq > VDAC_MAX_CLOCK) {
vdacFreq = VDAC_MAX_CLOCK;
}
if (vdac == VDAC0) {
refFreq = CMU_ClockFreqGet(cmuClock_VDAC0);
}
#if defined(VDAC1)
else if (vdac == VDAC1) {
refFreq = CMU_ClockFreqGet(cmuClock_VDAC1);
}
#endif
else {
EFM_ASSERT(0);
}
/* Iterate to determine the best prescaler value. Start with the lowest */
/* prescaler value to get the first equal or less VDAC */
/* frequency value. */
for (ret = 0; ret <= (_VDAC_CFG_PRESC_MASK >> _VDAC_CFG_PRESC_SHIFT); ret++) {
if ((refFreq / (ret + 1)) <= vdacFreq) {
break;
}
}
/* If ret is higher than the maximum prescaler value, make sure to return
the maximum value. */
if (ret > (_VDAC_CFG_PRESC_MASK >> _VDAC_CFG_PRESC_SHIFT)) {
ret = _VDAC_CFG_PRESC_MASK >> _VDAC_CFG_PRESC_SHIFT;
}
return ret;
}
#endif
/***************************************************************************//**
* @brief
* Reset VDAC to same state that it was in after a hardwares reset.
*
* @param[in] vdac
* A pointer to the VDAC peripheral register block.
******************************************************************************/
void VDAC_Reset(VDAC_TypeDef *vdac)
{
#if defined(VDAC_SWRST_SWRST)
while (vdac->STATUS & VDAC_STATUS_SYNCBUSY) {
}
/* Wait for all synchronizations to finish and disable the vdac channels */
if (vdac->EN & VDAC_EN_EN) {
vdac->CMD = _VDAC_CMD_CH0DIS_MASK;
while (vdac->STATUS & VDAC_STATUS_CH0ENS ) {
}
vdac->CMD = _VDAC_CMD_CH1DIS_MASK;
while (vdac->STATUS & VDAC_STATUS_CH1ENS ) {
}
while (vdac->STATUS & VDAC_STATUS_SYNCBUSY) {
}
vdac->CMD = _VDAC_CMD_CH0FIFOFLUSH_MASK | _VDAC_CMD_CH1FIFOFLUSH_MASK;
while (vdac->STATUS & (VDAC_STATUS_CH0FIFOFLBUSY | VDAC_STATUS_CH1FIFOFLBUSY)) {
}
while (vdac->STATUS & VDAC_STATUS_SYNCBUSY) {
}
}
vdac->SWRST_SET = VDAC_SWRST_SWRST;
while (vdac->SWRST & _VDAC_SWRST_RESETTING_MASK) {
}
#else
/* Disable channels before resetting other registers. */
vdac->CMD = VDAC_CMD_CH0DIS | VDAC_CMD_CH1DIS;
while (vdac->STATUS & (VDAC_STATUS_CH0ENS | VDAC_STATUS_CH1ENS)) {
}
vdac->CH0CTRL = _VDAC_CH0CTRL_RESETVALUE;
vdac->CH1CTRL = _VDAC_CH1CTRL_RESETVALUE;
vdac->CH0DATA = _VDAC_CH0DATA_RESETVALUE;
vdac->CH1DATA = _VDAC_CH1DATA_RESETVALUE;
vdac->CTRL = _VDAC_CTRL_RESETVALUE;
vdac->IEN = _VDAC_IEN_RESETVALUE;
vdac->IFC = _VDAC_IFC_MASK;
vdac->CAL = _VDAC_CAL_RESETVALUE;
#endif
}
/** @} (end addtogroup vdac) */
#endif /* defined(VDAC_COUNT) && (VDAC_COUNT > 0) */

View File

@@ -0,0 +1,355 @@
/***************************************************************************//**
* @file
* @brief Watchdog (WDOG) peripheral API
*******************************************************************************
* # License
* <b>Copyright 2018 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* 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_wdog.h"
#if defined(WDOG_COUNT) && (WDOG_COUNT > 0)
#include "em_bus.h"
#include "em_core.h"
/***************************************************************************//**
* @addtogroup wdog WDOG - Watchdog
* @brief Watchdog (WDOG) Peripheral API
* @details
* This module contains functions to control the WDOG peripheral of Silicon
* Labs 32-bit MCUs and SoCs. The WDOG resets the system in case of a fault
* condition.
* @{
******************************************************************************/
/** In some scenarioes when the watchdog is disabled the synchronization
* register might be set and not be cleared until the watchdog is enabled
* again. This will happen when for instance some watchdog register is modified
* while the watchdog clock is disabled. In these scenarioes we need to make
* sure that the software does not wait forever. */
#define WDOG_SYNC_TIMEOUT 30000
/*******************************************************************************
************************** GLOBAL FUNCTIONS *******************************
******************************************************************************/
/***************************************************************************//**
* @brief
* Enable/disable the watchdog timer.
*
* @note
* This function modifies the WDOG CTRL register which requires
* synchronization into the low-frequency domain. If this register is modified
* before a previous update to the same register has completed, this function
* will stall until the previous synchronization has completed.
*
* @param[in] wdog
* A pointer to the WDOG peripheral register block.
*
* @param[in] enable
* True to enable Watchdog, false to disable. Watchdog cannot be disabled if
* it's been locked.
******************************************************************************/
void WDOGn_Enable(WDOG_TypeDef *wdog, bool enable)
{
// SYNCBUSY may stall when locked.
#if defined(_WDOG_STATUS_MASK)
if ((wdog->STATUS & _WDOG_STATUS_LOCK_MASK) == WDOG_STATUS_LOCK_LOCKED) {
return;
}
#else
if (wdog->CTRL & WDOG_CTRL_LOCK) {
return;
}
#endif
#if defined(_WDOG_EN_MASK)
if (!enable) {
while (wdog->SYNCBUSY & WDOG_SYNCBUSY_CMD) {
}
wdog->EN_CLR = WDOG_EN_EN;
#if defined(_WDOG_EN_DISABLING_MASK)
while (wdog->EN & _WDOG_EN_DISABLING_MASK) {
}
#endif
} else {
wdog->EN_SET = WDOG_EN_EN;
}
#else
// Wait for previous operations/modifications to complete
int i = 0;
while (((wdog->SYNCBUSY & WDOG_SYNCBUSY_CTRL) != 0U)
&& (i < WDOG_SYNC_TIMEOUT)) {
i++;
}
bool wdogState = ((wdog->CTRL & _WDOG_CTRL_EN_MASK) != 0U);
// Make sure to only write to the CTRL register if we are changing mode
if (wdogState != enable) {
BUS_RegBitWrite(&wdog->CTRL, _WDOG_CTRL_EN_SHIFT, enable);
}
#endif
}
/***************************************************************************//**
* @brief
* Feed WDOG.
*
* @details
* When WDOG is activated, it must be fed (i.e., clearing the counter)
* before it reaches the defined timeout period. Otherwise, WDOG
* will generate a reset.
*
* @note
* Note that WDOG is an asynchronous peripheral and when calling the
* WDOGn_Feed() function the hardware starts the process of clearing the
* counter. This process takes some time before it completes depending on the
* selected oscillator (up to 4 peripheral clock cycles). When using the
* ULFRCO for instance as the oscillator the watchdog runs on a 1 kHz clock
* and a watchdog clear operation might take up to 4 ms.
*
* If the device enters EM2 or EM3 while a command is in progress then that
* command will be aborted. An application can use @ref WDOGn_SyncWait()
* to wait for a command to complete.
*
* @param[in] wdog
* A pointer to the WDOG peripheral register block.
******************************************************************************/
void WDOGn_Feed(WDOG_TypeDef *wdog)
{
#if (_SILICON_LABS_32B_SERIES < 2)
// WDOG should not be fed while it is disabled.
if (!(wdog->CTRL & WDOG_CTRL_EN)) {
return;
}
// If a previous clearing is synchronized to the LF domain, there
// is no point in waiting for it to complete before clearing over again.
// This avoids stalling the core in the typical use case where some idle loop
// keeps clearing WDOG.
if (wdog->SYNCBUSY & WDOG_SYNCBUSY_CMD) {
return;
}
// Before writing to the WDOG_CMD register, make sure that
// any previous write to the WDOG_CTRL is complete.
while ( (wdog->SYNCBUSY & WDOG_SYNCBUSY_CTRL) != 0U ) {
}
wdog->CMD = WDOG_CMD_CLEAR;
#else // Series 2 devices
CORE_DECLARE_IRQ_STATE;
// WDOG should not be fed while it is disabled.
if ((wdog->EN & WDOG_EN_EN) == 0U) {
return;
}
// We need an atomic section around the check for sync and the clear command
// because sending a clear command while a previous command is being synchronized
// will cause a BusFault.
CORE_ENTER_ATOMIC();
if ((wdog->SYNCBUSY & WDOG_SYNCBUSY_CMD) == 0U) {
wdog->CMD = WDOG_CMD_CLEAR;
}
CORE_EXIT_ATOMIC();
#endif
}
/***************************************************************************//**
* @brief
* Initialize WDOG (assuming the WDOG configuration has not been
* locked).
*
* @note
* This function modifies the WDOG CTRL register which requires
* synchronization into the low-frequency domain. If this register is modified
* before a previous update to the same register has completed, this function
* will stall until the previous synchronization has completed.
*
* @param[in] wdog
* Pointer to the WDOG peripheral register block.
*
* @param[in] init
* The structure holding the WDOG configuration. A default setting
* #WDOG_INIT_DEFAULT is available for initialization.
******************************************************************************/
void WDOGn_Init(WDOG_TypeDef *wdog, const WDOG_Init_TypeDef *init)
{
#if defined(_WDOG_CFG_MASK)
// Handle series-2 devices
if (wdog->EN != 0U) {
while (wdog->SYNCBUSY != 0U) {
// Wait for any potential synchronization to finish
}
wdog->EN_CLR = WDOG_EN_EN;
#if defined(_WDOG_EN_DISABLING_MASK)
while (wdog->EN & _WDOG_EN_DISABLING_MASK) {
/* Wait for disabling to finish */
}
#endif
}
wdog->CFG = (init->debugRun ? WDOG_CFG_DEBUGRUN : 0U)
| (init->clrSrc ? WDOG_CFG_CLRSRC : 0U)
#if defined(_WDOG_CFG_EM1RUN_MASK)
| (init->em1Run ? WDOG_CFG_EM1RUN : 0U)
#endif
| (init->em2Run ? WDOG_CFG_EM2RUN : 0U)
| (init->em3Run ? WDOG_CFG_EM3RUN : 0U)
| (init->em4Block ? WDOG_CFG_EM4BLOCK : 0U)
| (init->prs0MissRstEn ? WDOG_CFG_PRS0MISSRSTEN : 0U)
| (init->prs1MissRstEn ? WDOG_CFG_PRS1MISSRSTEN : 0U)
| (init->resetDisable ? WDOG_CFG_WDOGRSTDIS : 0U)
| ((uint32_t)(init->warnSel) << _WDOG_CFG_WARNSEL_SHIFT)
| ((uint32_t)(init->winSel) << _WDOG_CFG_WINSEL_SHIFT)
| ((uint32_t)(init->perSel) << _WDOG_CFG_PERSEL_SHIFT);
WDOGn_Enable(wdog, init->enable);
if (init->lock) {
WDOGn_Lock(wdog);
}
#else
// Handle series-0 and series-1 devices
uint32_t setting;
setting = (init->enable ? WDOG_CTRL_EN : 0U)
| (init->debugRun ? WDOG_CTRL_DEBUGRUN : 0U)
#if defined(_WDOG_CTRL_CLRSRC_MASK)
| (init->clrSrc ? WDOG_CTRL_CLRSRC : 0U)
#endif
| (init->em2Run ? WDOG_CTRL_EM2RUN : 0U)
| (init->em3Run ? WDOG_CTRL_EM3RUN : 0U)
| (init->em4Block ? WDOG_CTRL_EM4BLOCK : 0U)
| (init->swoscBlock ? WDOG_CTRL_SWOSCBLOCK : 0U)
| (init->lock ? WDOG_CTRL_LOCK : 0U)
| ((uint32_t)(init->clkSel) << _WDOG_CTRL_CLKSEL_SHIFT)
| ((uint32_t)(init->perSel) << _WDOG_CTRL_PERSEL_SHIFT);
#if defined(_WDOG_CTRL_WDOGRSTDIS_MASK)
setting |= (init->resetDisable ? WDOG_CTRL_WDOGRSTDIS : 0U);
#endif
#if defined(_WDOG_CTRL_WARNSEL_MASK)
setting |= ((uint32_t)(init->warnSel) << _WDOG_CTRL_WARNSEL_SHIFT);
#endif
#if defined(_WDOG_CTRL_WINSEL_MASK)
setting |= ((uint32_t)(init->winSel) << _WDOG_CTRL_WINSEL_SHIFT);
#endif
// Wait for previous operations/modifications to complete
int i = 0;
while (((wdog->SYNCBUSY & WDOG_SYNCBUSY_CTRL) != 0U)
&& (i < WDOG_SYNC_TIMEOUT)) {
i++;
}
wdog->CTRL = setting;
#endif
}
/***************************************************************************//**
* @brief
* Lock the WDOG configuration.
*
* @details
* This prevents errors from overwriting the WDOG configuration, possibly
* disabling it. Only a reset can unlock the WDOG configuration once locked.
*
* If the LFRCO or LFXO clocks are used to clock WDOG,
* consider using the option of inhibiting those clocks to be disabled.
* See the WDOG_Enable() initialization structure.
*
* @note
* This function modifies the WDOG CTRL register which requires
* synchronization into the low-frequency domain. If this register is modified
* before a previous update to the same register has completed, this function
* will stall until the previous synchronization has completed.
*
* @param[in] wdog
* A pointer to WDOG peripheral register block.
******************************************************************************/
void WDOGn_Lock(WDOG_TypeDef *wdog)
{
#if defined(_WDOG_LOCK_MASK)
wdog->LOCK = _WDOG_LOCK_LOCKKEY_LOCK;
#else
// Wait for any pending previous write operation to have been completed in
// the low-frequency domain.
while ( (wdog->SYNCBUSY & WDOG_SYNCBUSY_CTRL) != 0U ) {
}
// Disable writing to the control register.
BUS_RegBitWrite(&wdog->CTRL, _WDOG_CTRL_LOCK_SHIFT, 1);
#endif
}
/***************************************************************************//**
* @brief
* Wait for the WDOG to complete all synchronization of register changes
* and commands.
*
* @param[in] wdog
* A pointer to WDOG peripheral register block.
******************************************************************************/
void WDOGn_SyncWait(WDOG_TypeDef *wdog)
{
#if defined(_SILICON_LABS_32B_SERIES_2)
while ((wdog->EN != 0U) && (wdog->SYNCBUSY != 0U)) {
// Wait for synchronization to finish
}
#else
while (wdog->SYNCBUSY != 0U) {
// Wait for synchronization to finish
}
#endif
}
/***************************************************************************//**
* @brief
* Unlock the WDOG configuration.
*
* @details
* Note that this function will have no effect on devices where a reset is
* the only way to unlock the watchdog.
*
* @param[in] wdog
* A pointer to WDOG peripheral register block.
******************************************************************************/
void WDOGn_Unlock(WDOG_TypeDef *wdog)
{
#if defined(_WDOG_LOCK_MASK)
wdog->LOCK = _WDOG_LOCK_LOCKKEY_UNLOCK;
#else
(void) wdog;
#endif
}
/** @} (end addtogroup wdog) */
#endif /* defined(WDOG_COUNT) && (WDOG_COUNT > 0) */

View File

@@ -0,0 +1,32 @@
/***************************************************************************//**
* @file
* @brief System Real Time Counter (SYSRTC) peripheral API
*******************************************************************************
* # License
* <b>Copyright 2020 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* 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.
*
******************************************************************************/
// Compatibility layer. peripheral_sysrtc.h has been renamed to sl_hal_sysrtc.h
#include "sl_hal_sysrtc.h"

View File

@@ -0,0 +1,33 @@
/***************************************************************************//**
* @file
* @brief SYSRTC Compatibility Layer.
*******************************************************************************
* # License
* <b>Copyright 2023 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* 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.
*
******************************************************************************/
// Compatibility layer. peripheral_sysrtc_compat.h has been renamed to
// sl_hal_sysrtc_compat.h
#include "sl_hal_sysrtc_compat.h"

View File

@@ -0,0 +1,274 @@
/***************************************************************************//**
* @file
* @brief RAM and peripheral bit-field set, clear, read and write API.
*******************************************************************************
* # License
* <b>Copyright 2023 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* 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.
*
******************************************************************************/
#ifndef SL_HAL_BUS_H
#define SL_HAL_BUS_H
#include "sl_assert.h"
#include "sl_core.h"
#include "em_device.h"
#include "sl_code_classification.h"
#ifdef __cplusplus
extern "C" {
#endif
/***************************************************************************//**
* @addtogroup bus BUS - Bitfield Read/Write
* @brief BUS register and RAM bit-field read/write API
* @details
* API to perform field set/clear/write/read access to RAM and peripheral's registers.
* @{
******************************************************************************/
/***************************************************************************//**
* @brief
* Perform a single-bit write operation on a 32-bit word in RAM.
*
* @param[in] addr An address of a 32-bit word in RAM.
*
* @param[in] bit A bit position to write, 0-31.
*
* @param[in] val A value to set bit to, 0 or 1.
******************************************************************************/
__STATIC_INLINE void sl_hal_bus_ram_write_bit(volatile uint32_t *addr,
uint32_t bit,
uint32_t val)
{
uint32_t tmp = *addr;
/* Make sure val is not more than 1 because only one bit needs to be set. */
*addr = (tmp & ~(1UL << bit)) | ((val & 1UL) << bit);
}
/***************************************************************************//**
* @brief
* Perform a single-bit read operation on a 32-bit word in RAM.
*
* @param[in] addr RAM address.
*
* @param[in] bit A bit position to read, 0-31.
*
* @return
* The requested bit shifted to bit position 0 in the return value.
******************************************************************************/
__STATIC_INLINE unsigned int sl_hal_bus_ram_read_bit(volatile const uint32_t *addr,
uint32_t bit)
{
return ((*addr) >> bit) & 1UL;
}
/***************************************************************************//**
* @brief
* Perform a single-bit atomic write operation on a peripheral register.
*
* @details
* This function uses built-in hardware 4K-aliased addressing that allows to
* perform an atomic read-modify-write operation on a single register bit.
* See the reference manual for more details about alias addressing.
*
* @param[in] addr A peripheral register address.
*
* @param[in] bit A bit position to write, 0-31.
*
* @param[in] val A value to set bit to, 0 or 1.
******************************************************************************/
SL_CODE_CLASSIFY(SL_CODE_COMPONENT_HAL_COMMON, SL_CODE_CLASS_TIME_CRITICAL)
__STATIC_INLINE void sl_hal_bus_reg_write_bit(volatile uint32_t *addr,
uint32_t bit,
uint32_t val)
{
EFM_ASSERT(bit < 32U);
#if defined(PER_REG_BLOCK_SET_OFFSET) && defined(PER_REG_BLOCK_CLR_OFFSET)
uint32_t aliasAddr;
if (val != 0U) {
aliasAddr = (uint32_t)addr + PER_REG_BLOCK_SET_OFFSET;
} else {
aliasAddr = (uint32_t)addr + PER_REG_BLOCK_CLR_OFFSET;
}
*(volatile uint32_t *)aliasAddr = 1UL << bit;
#else
uint32_t tmp = *addr;
// Make sure val is not more than 1 because only one bit needs to be set.
*addr = (tmp & ~(1 << bit)) | ((val & 1) << bit);
#endif
}
/***************************************************************************//**
* @brief
* Perform a single-bit atomic read operation on a peripheral register.
*
* @param[in] addr A peripheral register address.
*
* @param[in] bit A bit position to read, 0-31.
*
* @return
* The requested bit shifted to bit position 0 in the return value.
******************************************************************************/
__STATIC_INLINE unsigned int sl_hal_bus_reg_read_bit(volatile const uint32_t *addr,
uint32_t bit)
{
return ((*addr) >> bit) & 1UL;
}
/***************************************************************************//**
* @brief
* Perform an atomic masked set operation on a peripheral register address.
*
* @details
* A peripheral register masked set provides a set operation of a bit-mask
* in a peripheral register. All 1s in the mask are set to 1 in the register.
* All 0s in the mask are not changed in the register.
* RAMs and special peripherals are not supported.
*
* @note
* This function uses built-in hardware 4K-aliased addressing that allows to
* perform an atomic read-modify-write operation.
* See the reference manual for more details about alias addressing.
*
* @param[in] addr A peripheral register address.
*
* @param[in] mask A mask to set.
******************************************************************************/
__STATIC_INLINE void sl_hal_bus_reg_set_mask(volatile uint32_t *addr,
uint32_t mask)
{
#if defined(PER_REG_BLOCK_SET_OFFSET)
uint32_t aliasAddr = (uint32_t)addr + PER_REG_BLOCK_SET_OFFSET;
*(volatile uint32_t *)aliasAddr = mask;
#else
CORE_DECLARE_IRQ_STATE;
CORE_ENTER_CRITICAL();
*addr |= mask;
CORE_EXIT_CRITICAL();
#endif
}
/***************************************************************************//**
* @brief
* Perform an atomic masked clear operation on the peripheral register address.
*
* @details
* A peripheral register masked clear provides a clear operation of a bit-mask
* in a peripheral register. All 1s in the mask are set to 0 in the register.
* All 0s in the mask are not changed in the register.
* RAMs and special peripherals are not supported.
*
* @note
* This function uses built-in hardware 4K-aliased addressing that allows to
* perform an atomic read-modify-write operation.
* See the reference manual for more details about alias addressing.
*
* @param[in] addr A peripheral register address.
*
* @param[in] mask A mask to clear.
******************************************************************************/
__STATIC_INLINE void sl_hal_bus_reg_clear_mask(volatile uint32_t *addr,
uint32_t mask)
{
#if defined(PER_REG_BLOCK_CLR_OFFSET)
uint32_t aliasAddr = (uint32_t)addr + PER_REG_BLOCK_CLR_OFFSET;
*(volatile uint32_t *)aliasAddr = mask;
#else
CORE_DECLARE_IRQ_STATE;
CORE_ENTER_CRITICAL();
*addr &= ~mask;
CORE_EXIT_CRITICAL();
#endif
}
/***************************************************************************//**
* @brief
* Perform peripheral register masked write.
*
* @details
* This function first reads the peripheral register and updates only bits
* that are set in the mask with content of val. Typically, the mask is a
* bit-field in the register and the value val is within the mask.
*
* @note
* The read-modify-write operation is executed in a critical section to
* guarantee atomicity. Note that atomicity can only be guaranteed if register
* is modified only by the core, and not by other peripherals (like DMA).
*
* @param[in] addr A peripheral register address.
*
* @param[in] mask A peripheral register mask.
*
* @param[in] val A peripheral register value. The value must be shifted to the
correct bit position in the register corresponding to the field
defined by the mask parameter. The register value must be
contained in the field defined by the mask parameter. The
register value is masked to prevent involuntary spillage.
******************************************************************************/
__STATIC_INLINE void sl_hal_bus_reg_write_mask(volatile uint32_t *addr,
uint32_t mask,
uint32_t val)
{
CORE_DECLARE_IRQ_STATE;
CORE_ENTER_CRITICAL();
*addr = (*addr & ~mask) | (val & mask);
CORE_EXIT_CRITICAL();
}
/***************************************************************************//**
* @brief
* Perform a peripheral register masked read.
*
* @details
* Read an unshifted and masked value from a peripheral register.
*
* @note
* This operation is not hardware accelerated.
*
* @param[in] addr A peripheral register address.
*
* @param[in] mask A peripheral register mask.
*
* @return
* An unshifted and masked register value.
******************************************************************************/
__STATIC_INLINE uint32_t sl_hal_bus_reg_read_mask(volatile const uint32_t *addr,
uint32_t mask)
{
return *addr & mask;
}
/** @} (end addtogroup bus) */
#ifdef __cplusplus
}
#endif
#endif /* SL_HAL_BUS_H */

View File

@@ -0,0 +1,915 @@
/***************************************************************************//**
* @file
* @brief General Purpose IO (GPIO) peripheral API
*******************************************************************************
* # License
* <b>Copyright 2018 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* 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.
*
******************************************************************************/
#ifndef SL_HAL_GPIO_H
#define SL_HAL_GPIO_H
#include "em_device.h"
#if defined(GPIO_PRESENT)
#ifdef __cplusplus
extern "C" {
#endif
#include <stdbool.h>
#include <stddef.h>
#include "sl_assert.h"
#include "sl_device_gpio.h"
#include "sl_code_classification.h"
/* *INDENT-OFF* */
// *****************************************************************************
/// @addtogroup gpio GPIO - General Purpose Input Output
/// @brief General Purpose Input Output peripheral
///
/// @li @ref gpio_intro
///
///@n @section gpio_intro Introduction
/// This module contains functions to control the GPIO peripheral of Silicon Labs 32-bit MCUs and SoCs.
/// The GPIO peripheral is used for interrupt configuration, pin configuration and direct pin manipulation
/// as well as routing for peripheral pin connections.
///
/// @{
// *****************************************************************************
/* *INDENT-ON* */
/*******************************************************************************
******************************** DEFINES **********************************
******************************************************************************/
/// Define for port specific pin mask
#if defined(GPIO_PA_MASK)
#define SL_HAL_GPIO_PORT_A_PIN_MASK (GPIO_PA_MASK)
#else
#define SL_HAL_GPIO_PORT_A_PIN_MASK 0
#endif
#if defined(GPIO_PB_MASK)
#define SL_HAL_GPIO_PORT_B_PIN_MASK (GPIO_PB_MASK)
#else
#define SL_HAL_GPIO_PORT_B_PIN_MASK 0
#endif
#if defined(GPIO_PC_MASK)
#define SL_HAL_GPIO_PORT_C_PIN_MASK (GPIO_PC_MASK)
#else
#define SL_HAL_GPIO_PORT_C_PIN_MASK 0
#endif
#if defined(GPIO_PD_MASK)
#define SL_HAL_GPIO_PORT_D_PIN_MASK (GPIO_PD_MASK)
#else
#define SL_HAL_GPIO_PORT_D_PIN_MASK 0
#endif
#if defined(GPIO_PE_MASK)
#define SL_HAL_GPIO_PORT_E_PIN_MASK (GPIO_PE_MASK)
#else
#define SL_HAL_GPIO_PORT_E_PIN_MASK 0
#endif
#if defined(GPIO_PF_MASK)
#define SL_HAL_GPIO_PORT_F_PIN_MASK (GPIO_PF_MASK)
#else
#define SL_HAL_GPIO_PORT_F_PIN_MASK 0
#endif
#if defined(GPIO_PG_MASK)
#define SL_HAL_GPIO_PORT_G_PIN_MASK (GPIO_PG_MASK)
#else
#define SL_HAL_GPIO_PORT_G_PIN_MASK 0
#endif
#if defined(GPIO_PH_MASK)
#define SL_HAL_GPIO_PORT_H_PIN_MASK (GPIO_PH_MASK)
#else
#define SL_HAL_GPIO_PORT_H_PIN_MASK 0
#endif
#if defined(GPIO_PI_MASK)
#define SL_HAL_GPIO_PORT_I_PIN_MASK (GPIO_PI_MASK)
#else
#define SL_HAL_GPIO_PORT_I_PIN_MASK 0
#endif
#if defined(GPIO_PJ_MASK)
#define SL_HAL_GPIO_PORT_J_PIN_MASK (GPIO_PJ_MASK)
#else
#define SL_HAL_GPIO_PORT_J_PIN_MASK 0
#endif
#if defined(GPIO_PK_MASK)
#define SL_HAL_GPIO_PORT_K_PIN_MASK (GPIO_PK_MASK)
#else
#define SL_HAL_GPIO_PORT_K_PIN_MASK 0
#endif
/// Define for port specific pin count
#if defined(GPIO_PA_COUNT)
#define SL_HAL_GPIO_PORT_A_PIN_COUNT (GPIO_PA_COUNT)
#else
#define SL_HAL_GPIO_PORT_A_PIN_COUNT 0
#endif
#if defined(GPIO_PB_COUNT)
#define SL_HAL_GPIO_PORT_B_PIN_COUNT (GPIO_PB_COUNT)
#else
#define SL_HAL_GPIO_PORT_B_PIN_COUNT 0
#endif
#if defined(GPIO_PC_COUNT)
#define SL_HAL_GPIO_PORT_C_PIN_COUNT (GPIO_PC_COUNT)
#else
#define SL_HAL_GPIO_PORT_C_PIN_COUNT 0
#endif
#if defined(GPIO_PD_COUNT)
#define SL_HAL_GPIO_PORT_D_PIN_COUNT (GPIO_PD_COUNT)
#else
#define SL_HAL_GPIO_PORT_D_PIN_COUNT 0
#endif
#if defined(GPIO_PE_COUNT)
#define SL_HAL_GPIO_PORT_E_PIN_COUNT (GPIO_PE_COUNT)
#else
#define SL_HAL_GPIO_PORT_E_PIN_COUNT 0
#endif
#if defined(GPIO_PF_COUNT)
#define SL_HAL_GPIO_PORT_F_PIN_COUNT (GPIO_PF_COUNT)
#else
#define SL_HAL_GPIO_PORT_F_PIN_COUNT 0
#endif
#if defined(GPIO_PG_COUNT)
#define SL_HAL_GPIO_PORT_G_PIN_COUNT (GPIO_PG_COUNT)
#else
#define SL_HAL_GPIO_PORT_G_PIN_COUNT 0
#endif
#if defined(GPIO_PH_COUNT)
#define SL_HAL_GPIO_PORT_H_PIN_COUNT (GPIO_PH_COUNT)
#else
#define SL_HAL_GPIO_PORT_H_PIN_COUNT 0
#endif
#if defined(GPIO_PI_COUNT)
#define SL_HAL_GPIO_PORT_I_PIN_COUNT (GPIO_PI_COUNT)
#else
#define SL_HAL_GPIO_PORT_I_PIN_COUNT 0
#endif
#if defined(GPIO_PJ_COUNT)
#define SL_HAL_GPIO_PORT_J_PIN_COUNT (GPIO_PJ_COUNT)
#else
#define SL_HAL_GPIO_PORT_J_PIN_COUNT 0
#endif
#if defined(GPIO_PK_COUNT)
#define SL_HAL_GPIO_PORT_K_PIN_COUNT (GPIO_PK_COUNT)
#else
#define SL_HAL_GPIO_PORT_K_PIN_COUNT 0
#endif
/// @cond DO_NOT_INCLUDE_WITH_DOXYGEN
/// Highest GPIO port number.
#if (SL_HAL_GPIO_PORT_K_PIN_COUNT > 0)
#define SL_HAL_GPIO_PORT_MAX 10
#elif (SL_HAL_GPIO_PORT_J_PIN_COUNT > 0)
#define SL_HAL_GPIO_PORT_MAX 9
#elif (SL_HAL_GPIO_PORT_I_PIN_COUNT > 0)
#define SL_HAL_GPIO_PORT_MAX 8
#elif (SL_HAL_GPIO_PORT_H_PIN_COUNT > 0)
#define SL_HAL_GPIO_PORT_MAX 7
#elif (SL_HAL_GPIO_PORT_G_PIN_COUNT > 0)
#define SL_HAL_GPIO_PORT_MAX 6
#elif (SL_HAL_GPIO_PORT_F_PIN_COUNT > 0)
#define SL_HAL_GPIO_PORT_MAX 5
#elif (SL_HAL_GPIO_PORT_E_PIN_COUNT > 0)
#define SL_HAL_GPIO_PORT_MAX 4
#elif (SL_HAL_GPIO_PORT_D_PIN_COUNT > 0)
#define SL_HAL_GPIO_PORT_MAX 3
#elif (SL_HAL_GPIO_PORT_C_PIN_COUNT > 0)
#define SL_HAL_GPIO_PORT_MAX 2
#elif (SL_HAL_GPIO_PORT_B_PIN_COUNT > 0)
#define SL_HAL_GPIO_PORT_MAX 1
#elif (SL_HAL_GPIO_PORT_A_PIN_COUNT > 0)
#define SL_HAL_GPIO_PORT_MAX 0
#else
#error "Max GPIO port number is undefined for this part."
#endif
/// Highest GPIO pin number.
#define SL_HAL_GPIO_PIN_MAX 15
/// @endcond
#define SL_HAL_GPIO_PORT_SIZE(port) ( \
(port) == 0 ? SL_HAL_GPIO_PORT_A_PIN_COUNT \
: (port) == 1 ? SL_HAL_GPIO_PORT_B_PIN_COUNT \
: (port) == 2 ? SL_HAL_GPIO_PORT_C_PIN_COUNT \
: (port) == 3 ? SL_HAL_GPIO_PORT_D_PIN_COUNT \
: (port) == 4 ? SL_HAL_GPIO_PORT_E_PIN_COUNT \
: (port) == 5 ? SL_HAL_GPIO_PORT_F_PIN_COUNT \
: (port) == 6 ? SL_HAL_GPIO_PORT_G_PIN_COUNT \
: (port) == 7 ? SL_HAL_GPIO_PORT_H_PIN_COUNT \
: (port) == 8 ? SL_HAL_GPIO_PORT_I_PIN_COUNT \
: (port) == 9 ? SL_HAL_GPIO_PORT_J_PIN_COUNT \
: (port) == 10 ? SL_HAL_GPIO_PORT_K_PIN_COUNT \
: 0)
#define SL_HAL_GPIO_PORT_MASK(port) ( \
((int)port) == 0 ? SL_HAL_GPIO_PORT_A_PIN_MASK \
: ((int)port) == 1 ? SL_HAL_GPIO_PORT_B_PIN_MASK \
: ((int)port) == 2 ? SL_HAL_GPIO_PORT_C_PIN_MASK \
: ((int)port) == 3 ? SL_HAL_GPIO_PORT_D_PIN_MASK \
: ((int)port) == 4 ? SL_HAL_GPIO_PORT_E_PIN_MASK \
: ((int)port) == 5 ? SL_HAL_GPIO_PORT_F_PIN_MASK \
: ((int)port) == 6 ? SL_HAL_GPIO_PORT_G_PIN_MASK \
: ((int)port) == 7 ? SL_HAL_GPIO_PORT_H_PIN_MASK \
: ((int)port) == 8 ? SL_HAL_GPIO_PORT_I_PIN_MASK \
: ((int)port) == 9 ? SL_HAL_GPIO_PORT_J_PIN_MASK \
: ((int)port) == 10 ? SL_HAL_GPIO_PORT_K_PIN_MASK \
: 0UL)
/// Validation of port.
#define SL_HAL_GPIO_PORT_IS_VALID(port) (SL_HAL_GPIO_PORT_MASK(port) != 0x0UL)
/// Validation of port and pin.
#define SL_HAL_GPIO_PORT_PIN_IS_VALID(port, pin) ((((SL_HAL_GPIO_PORT_MASK(port)) >> (pin)) & 0x1UL) == 0x1UL)
/// Max interrupt lines for external and EM4 interrupts.
#define SL_HAL_GPIO_INTERRUPT_MAX 15
/// Shift value for EM4WUEN
#define SL_HAL_GPIO_EM4WUEN_SHIFT _GPIO_EM4WUEN_EM4WUEN_SHIFT
/// Masks for even and odd interrupt bits.
#define SL_HAL_GPIO_INT_IF_EVEN_MASK ((_GPIO_IF_MASK) & 0x55555555UL)
#define SL_HAL_GPIO_INT_IF_ODD_MASK ((_GPIO_IF_MASK) & 0xAAAAAAAAUL)
/// Validation of mode.
#define SL_HAL_GPIO_MODE_IS_VALID(mode) ((mode & _GPIO_P_MODEL_MODE0_MASK) == mode)
/// Validation of interrupt number and pin.
#define SL_HAL_GPIO_INTNO_PIN_VALID(int_no, pin) (((int_no) & ~_GPIO_EXTIPINSELL_EXTIPINSEL0_MASK) == ((pin) & ~_GPIO_EXTIPINSELL_EXTIPINSEL0_MASK))
/*******************************************************************************
******************************** ENUMS ************************************
******************************************************************************/
/*******************************************************************************
***************************** PROTOTYPES **********************************
******************************************************************************/
/***************************************************************************//**
* Set the mode for a GPIO pin.
*
* @param[in] gpio Pointer to GPIO structure with port and pin
* @param[in] mode The desired pin mode.
* @param[in] output_value A value to set for the pin in the DOUT register. The DOUT setting is important for
* some input mode configurations to determine the pull-up/down direction.
******************************************************************************/
void sl_hal_gpio_set_pin_mode(const sl_gpio_t *gpio,
sl_gpio_mode_t mode,
bool output_value);
/***************************************************************************//**
* Get the mode for a GPIO pin.
*
* @param[in] gpio Pointer to GPIO structure with port and pin
*
* @return Return the pin mode.
******************************************************************************/
sl_gpio_mode_t sl_hal_gpio_get_pin_mode(const sl_gpio_t *gpio);
/***************************************************************************//**
* Configure the GPIO external pin interrupt by connecting external interrupt id with gpio pin.
*
* @note This function configure the pin interrupt with pin ,port and external interrupt id as input.
* If external interrupt id is provided as input it will be considered as the input or else
* available interrupt number will be generated by looping through the interrupt group and will be used.
* User can provide SL_HAL_GPIO_INTERRUPT_UNAVAILABLE if user don't want to provide interrupt id.
* @note the pin number can be selected freely within a group.
* Interrupt numbers are divided into 4 groups (int_no / 4) and valid pin
* number within the interrupt groups are:
* 0: pins 0-3 (interrupt number 0-3)
* 1: pins 4-7 (interrupt number 4-7)
* 2: pins 8-11 (interrupt number 8-11)
* 3: pins 12-15 (interrupt number 12-15)
* @note It is recommended to disable interrupts before configuring the GPIO pin interrupt.
* See @ref sl_hal_gpio_disable_interrupts() for more information.
* The GPIO interrupt handler must be in place before enabling the interrupt.
* Notice that any pending interrupt for the selected interrupt is cleared by this function.
* Notice that only interrupt will be configured by this function. It is not enabled.
* It is recommended to enable interrupts after configuring the GPIO pin interrupt if needed.
* See @ref sl_hal_gpio_enable_interrupts() for more information.
*
* @param[in] gpio Pointer to GPIO structure with port and pin
* @param[in] int_no The interrupt number to trigger.
* @param[in] flags Interrupt configuration flags. @ref sl_hal_gpio_interrupt_flag_t for more information.
*
* @return Return the available interrupt number
******************************************************************************/
int32_t sl_hal_gpio_configure_external_interrupt(const sl_gpio_t *gpio,
int32_t int_no,
sl_gpio_interrupt_flag_t flags);
/**************************************************************************//**
* Enable GPIO pin wake-up from EM4. When the function exits,
* EM4 mode can be safely entered.
*
* @note It is assumed that the GPIO pin modes are set correctly.
* Valid modes are SL_GPIO_MODE_INPUT and SL_GPIO_MODE_INPUT_PULL.
*
* @param[in] pinmask A bitmask containing the bitwise logic OR of which GPIO pin(s) to enable.
* @param[in] polaritymask A bitmask containing the bitwise logic OR of GPIO pin(s) wake-up polarity.
*****************************************************************************/
void sl_hal_gpio_enable_pin_em4_wakeup(uint32_t pinmask,
uint32_t polaritymask);
/***************************************************************************//**
* Configure EM4WU pins as external level-sensitive interrupts.
*
* @note It is recommended to disable interrupts before configuring the GPIO pin interrupt.
* See @ref sl_hal_gpio_disable_interrupts() for more information.
* The provided port, pin and int_no inputs should be valid EM4 related parameters
* because there are dedicated port, pin and EM4 Wakeup interrupt combination for
* configuring the port, pin for EM4 functionality.
* User can provide SL_HAL_GPIO_INTERRUPT_UNAVAILABLE if user don't want to provide interrupt id.
* The GPIO interrupt handler must be in place before enabling the interrupt.
* Notice that any pending interrupt for the selected interrupt is cleared by this function.
* Notice that any only EM4WU interrupt is configured by this function. It is not enabled.
* It is recommended to enable interrupts after configuring the GPIO pin interrupt if needed.
* See @ref sl_hal_gpio_enable_interrupts() for more information.
*
* @param[in] gpio Pointer to GPIO structure with port and pin
* @param[in] int_no The EM4WU interrupt number to trigger.
* @param[in] polarity true = Active high level-sensitive interrupt.
* false = Active low level-sensitive interrupt.
*
* @return Return the available EM4WU interrupt number
******************************************************************************/
int32_t sl_hal_gpio_configure_wakeup_em4_external_interrupt(const sl_gpio_t *gpio,
int32_t int_no,
bool polarity);
/***************************************************************************//**
* Lock the GPIO configuration.
*
* @note Configuration lock affects the GPIO_Px_MODEL, GPIO_Px_MODEH, GPIO_Px_CTRL,
* GPIO_Px_PINLOCKN, GPIO_EXTIPSELL, GPIO_EXTIPSELH, GPIO_EXTIPINSELL,
* GPIO_EXTIPINSELH, GPIO_INSENSE, GPIO_ROUTE, GPIO_ROUTEPEN, and
* GPIO_ROUTELOC0 registers when they are present on a specific device.
* @note Unwanted or accidental changes to GPIO configuration can be avoided by
* using the configuration lock register. Any value other than 0xA534 written to
* GPIO_LOCK enables the configuration lock. Pins are unlocked by a reset or
* by writing 0xA534 to the GPIO_LOCK register.
******************************************************************************/
__INLINE void sl_hal_gpio_lock(void)
{
GPIO->LOCK = ~GPIO_LOCK_LOCKKEY_UNLOCK;
}
/***************************************************************************//**
* Unlock the GPIO configuration.
*
* @note Configuration lock affects the GPIO_Px_MODEL, GPIO_Px_MODEH, GPIO_Px_CTRL,
* GPIO_Px_PINLOCKN, GPIO_EXTIPSELL, GPIO_EXTIPSELH, GPIO_EXTIPINSELL,
* GPIO_EXTIPINSELH, GPIO_INSENSE, GPIO_ROUTE, GPIO_ROUTEPEN, and
* GPIO_ROUTELOC0 registers when they are present on a specific device.
* @note Unwanted or accidental changes to GPIO configuration can be avoided by
* using the configuration lock register. Any value other than 0xA534 written to
* GPIO_LOCK enables the configuration lock. Pins are unlocked by a reset or
* by writing 0xA534 to the GPIO_LOCK register.
******************************************************************************/
__INLINE void sl_hal_gpio_unlock(void)
{
GPIO->LOCK = GPIO_LOCK_LOCKKEY_UNLOCK;
}
/***************************************************************************//**
* Gets the GPIO configuration state.
*
* @return Return the GPIO lock state.
******************************************************************************/
__INLINE uint32_t sl_hal_gpio_get_lock_status(void)
{
return GPIO->GPIOLOCKSTATUS;
}
/***************************************************************************//**
* Set a single pin in GPIO data out register to 1.
*
* @param[in] gpio Pointer to GPIO structure with port and pin
******************************************************************************/
SL_CODE_CLASSIFY(SL_CODE_COMPONENT_HAL_GPIO, SL_CODE_CLASS_TIME_CRITICAL)
__INLINE void sl_hal_gpio_set_pin(const sl_gpio_t *gpio)
{
EFM_ASSERT(gpio != NULL);
EFM_ASSERT(SL_HAL_GPIO_PORT_PIN_IS_VALID(gpio->port, gpio->pin));
GPIO->P_SET[gpio->port].DOUT = 1UL << gpio->pin;
}
/***************************************************************************//**
* Set bits GPIO data out register to 1.
*
* @param[in] port The GPIO port to access.
* @param[in] pins Bit mask for bits to set to 1 in DOUT register.
******************************************************************************/
__INLINE void sl_hal_gpio_set_port(sl_gpio_port_t port,
uint32_t pins)
{
EFM_ASSERT(SL_HAL_GPIO_PORT_IS_VALID(port));
GPIO->P_SET[port].DOUT = pins;
}
/***************************************************************************//**
* Set GPIO port data out register.
*
* @param[in] port The GPIO port to access.
* @param[in] val Value to write to port data out register.
* @param[in] mask Mask indicating which bits to modify.
******************************************************************************/
__INLINE void sl_hal_gpio_set_port_value(sl_gpio_port_t port,
uint32_t val,
uint32_t mask)
{
EFM_ASSERT(SL_HAL_GPIO_PORT_IS_VALID(port));
GPIO->P[port].DOUT = (GPIO->P[port].DOUT & ~mask) | (val & mask);
}
/***************************************************************************//**
* Set slewrate for pins on a GPIO port which are configured into normal modes.
*
* @param[in] port The GPIO port to configure.
* @param[in] slewrate The slewrate to configure for pins on this GPIO port.
******************************************************************************/
__INLINE void sl_hal_gpio_set_slew_rate(sl_gpio_port_t port,
uint8_t slewrate)
{
EFM_ASSERT(SL_HAL_GPIO_PORT_IS_VALID(port));
EFM_ASSERT(slewrate <= (_GPIO_P_CTRL_SLEWRATE_MASK
>> _GPIO_P_CTRL_SLEWRATE_SHIFT));
GPIO->P[port].CTRL = (GPIO->P[port].CTRL
& ~_GPIO_P_CTRL_SLEWRATE_MASK)
| (slewrate << _GPIO_P_CTRL_SLEWRATE_SHIFT);
}
/***************************************************************************//**
* Set slewrate for pins on a GPIO port which are configured into alternate modes.
*
* @param[in] port The GPIO port to configure.
* @param[in] slewrate_alt The slewrate to configure for pins using alternate modes on this GPIO port.
******************************************************************************/
__INLINE void sl_hal_gpio_set_slew_rate_alternate(sl_gpio_port_t port,
uint8_t slewrate_alt)
{
EFM_ASSERT(SL_HAL_GPIO_PORT_IS_VALID(port));
EFM_ASSERT(slewrate_alt <= (_GPIO_P_CTRL_SLEWRATEALT_MASK
>> _GPIO_P_CTRL_SLEWRATEALT_SHIFT));
GPIO->P[port].CTRL = (GPIO->P[port].CTRL
& ~_GPIO_P_CTRL_SLEWRATEALT_MASK)
| (slewrate_alt << _GPIO_P_CTRL_SLEWRATEALT_SHIFT);
}
/***************************************************************************//**
* Get slewrate for pins on a GPIO port.
*
* @param[in] port The GPIO port to access to get slew rate.
*
* @return Return the slewrate setting for the selected GPIO port.
******************************************************************************/
__INLINE uint8_t sl_hal_gpio_get_slew_rate(sl_gpio_port_t port)
{
EFM_ASSERT(SL_HAL_GPIO_PORT_IS_VALID(port));
return (GPIO->P[port].CTRL & _GPIO_P_CTRL_SLEWRATE_MASK) >> _GPIO_P_CTRL_SLEWRATE_SHIFT;
}
/***************************************************************************//**
* Get slewrate for pins on a GPIO port which are configured into alternate modes.
*
* @param[in] port The GPIO port to access to get slew rate.
*
* @return Return the alternate slewrate setting for selected GPIO port.
******************************************************************************/
__INLINE uint8_t sl_hal_gpio_get_slew_rate_alternate(sl_gpio_port_t port)
{
EFM_ASSERT(SL_HAL_GPIO_PORT_IS_VALID(port));
return (GPIO->P[port].CTRL & _GPIO_P_CTRL_SLEWRATEALT_MASK) >> _GPIO_P_CTRL_SLEWRATEALT_SHIFT;
}
/***************************************************************************//**
* Set a single pin in GPIO data out port register to 0.
*
* @param[in] gpio Pointer to GPIO structure with port and pin
******************************************************************************/
__INLINE void sl_hal_gpio_clear_pin(const sl_gpio_t *gpio)
{
EFM_ASSERT(gpio != NULL);
EFM_ASSERT(SL_HAL_GPIO_PORT_PIN_IS_VALID(gpio->port, gpio->pin));
GPIO->P_CLR[gpio->port].DOUT = 1UL << gpio->pin;
}
/***************************************************************************//**
* Set bits in DOUT register for a port to 0.
*
* @param[in] port The GPIO port to access.
* @param[in] pins Bit mask for bits to clear in DOUT register.
******************************************************************************/
__INLINE void sl_hal_gpio_clear_port(sl_gpio_port_t port,
uint32_t pins)
{
EFM_ASSERT(SL_HAL_GPIO_PORT_IS_VALID(port));
GPIO->P_CLR[port].DOUT = pins;
}
/***************************************************************************//**
* Read the pad value for a single pin in a GPIO port.
*
* @param[in] gpio Pointer to GPIO structure with port and pin.
*
* @return The pin value, 0 or 1.
******************************************************************************/
__INLINE bool sl_hal_gpio_get_pin_input(const sl_gpio_t *gpio)
{
EFM_ASSERT(gpio != NULL);
EFM_ASSERT(SL_HAL_GPIO_PORT_PIN_IS_VALID(gpio->port, gpio->pin));
bool pin_input = ((GPIO->P[gpio->port].DIN) >> gpio->pin) & 1UL;
return pin_input;
}
/***************************************************************************//**
* Get current setting for a pin in a GPIO port data out register.
*
* @param[in] gpio Pointer to GPIO structure with port and pin.
*
* @return The DOUT setting for the requested pin, 0 or 1.
******************************************************************************/
__INLINE bool sl_hal_gpio_get_pin_output(const sl_gpio_t *gpio)
{
EFM_ASSERT(gpio != NULL);
EFM_ASSERT(SL_HAL_GPIO_PORT_PIN_IS_VALID(gpio->port, gpio->pin));
bool pin_output = ((GPIO->P[gpio->port].DOUT) >> gpio->pin) & 1UL;
return pin_output;
}
/***************************************************************************//**
* Read the pad values for GPIO port.
*
* @param[in] port The GPIO port to access.
*
* @return The pad values for the GPIO port.
******************************************************************************/
__INLINE uint32_t sl_hal_gpio_get_port_input(sl_gpio_port_t port)
{
EFM_ASSERT(SL_HAL_GPIO_PORT_IS_VALID(port));
return GPIO->P[port].DIN;
}
/***************************************************************************//**
* Get current setting for a GPIO port data out register.
*
* @param[in] port The GPIO port to access.
*
* @return The data out setting for the requested port.
******************************************************************************/
__INLINE uint32_t sl_hal_gpio_get_port_output(sl_gpio_port_t port)
{
EFM_ASSERT(SL_HAL_GPIO_PORT_IS_VALID(port));
return GPIO->P[port].DOUT;
}
/***************************************************************************//**
* Toggle a single pin in GPIO port data out register.
*
* @param[in] gpio Pointer to GPIO structure with port and pin.
******************************************************************************/
__INLINE void sl_hal_gpio_toggle_pin(const sl_gpio_t *gpio)
{
EFM_ASSERT(gpio != NULL);
EFM_ASSERT(SL_HAL_GPIO_PORT_PIN_IS_VALID(gpio->port, gpio->pin));
GPIO->P_TGL[gpio->port].DOUT = 1UL << gpio->pin;
}
/***************************************************************************//**
* Toggle pins in GPIO port data out register.
*
* @param[in] port The GPIO port to access.
* @param[in] pins Bit mask with pins to toggle.
******************************************************************************/
__INLINE void sl_hal_gpio_toggle_port(sl_gpio_port_t port,
uint32_t pins)
{
EFM_ASSERT(SL_HAL_GPIO_PORT_IS_VALID(port));
GPIO->P_TGL[port].DOUT = pins;
}
/***************************************************************************//**
* Enable one or more GPIO interrupts.
*
* @param[in] flags GPIO interrupt sources to enable.
******************************************************************************/
__INLINE void sl_hal_gpio_enable_interrupts(uint32_t flags)
{
GPIO->IEN_SET = flags;
}
/***************************************************************************//**
* Disable one or more GPIO interrupts.
*
* @param[in] flags GPIO interrupt sources to disable.
******************************************************************************/
__INLINE void sl_hal_gpio_disable_interrupts(uint32_t flags)
{
GPIO->IEN_CLR = flags;
}
/***************************************************************************//**
* Clear one or more pending GPIO interrupts.
*
* @param[in] flags Bitwise logic OR of GPIO interrupt sources to clear.
******************************************************************************/
__INLINE void sl_hal_gpio_clear_interrupts(uint32_t flags)
{
GPIO->IF_CLR = flags;
}
/**************************************************************************//**
* Set one or more pending GPIO interrupts from SW.
*
* @param[in] flags GPIO interrupt sources to set to pending.
*****************************************************************************/
__INLINE void sl_hal_gpio_set_interrupts(uint32_t flags)
{
GPIO->IF_SET = flags;
}
/***************************************************************************//**
* Get pending GPIO interrupts.
*
* @return GPIO interrupt sources pending.
******************************************************************************/
__INLINE uint32_t sl_hal_gpio_get_pending_interrupts(void)
{
return GPIO->IF;
}
/***************************************************************************//**
* Get enabled GPIO interrupts.
*
* @return Enabled GPIO interrupt sources.
******************************************************************************/
__INLINE uint32_t sl_hal_gpio_get_enabled_interrupts(void)
{
return GPIO->IEN;
}
/***************************************************************************//**
* Get enabled and pending GPIO interrupt flags.
*
* @return Enabled and pending interrupt sources.
*
* @note Useful for handling more interrupt sources in the same interrupt handler.
******************************************************************************/
__INLINE uint32_t sl_hal_gpio_get_enabled_pending_interrupts(void)
{
uint32_t tmp;
tmp = GPIO->IEN;
return GPIO->IF & tmp;
}
/***************************************************************************//**
* The available external interrupt number getter.
*
* @param[in] pin The GPIO pin to access.
* @param[in] enabled_interrupts_mask Contains enabled GPIO interrupts mask.
*
* @return The available interrupt number based on interrupt and pin grouping.
******************************************************************************/
__INLINE int32_t sl_hal_gpio_get_external_interrupt_number(uint8_t pin,
uint32_t enabled_interrupts_mask)
{
uint32_t interrupt_to_check;
uint32_t int_group_start = (pin & 0xFFC);
int32_t int_no = -1;
// loop through the interrupt group, starting
// from the pin number, and take
// the first available.
for (uint8_t i = 0; i < 4; i++) {
interrupt_to_check = int_group_start + ((pin + i) & 0x3); // modulo 4
if (((enabled_interrupts_mask >> interrupt_to_check) & 0x1) == 0) {
int_no = interrupt_to_check;
break;
}
}
return int_no;
}
/***************************************************************************//**
* The available em4 wakeup interrupt number getter.
*
* @param[in] gpio Pointer to GPIO structure with port and pin.
*
* @return The available em4 wakeup interrupt number based on associated port and pin.
******************************************************************************/
__INLINE int32_t sl_hal_gpio_get_em4_interrupt_number(const sl_gpio_t *gpio)
{
EFM_ASSERT(gpio != NULL);
int32_t em4_int_no;
if (false) {
// Check all the EM4WU Pins and check if given port, pin matches any of them.
#if defined(GPIO_EM4WU0_PORT)
} else if (GPIO_EM4WU0_PORT == gpio->port && GPIO_EM4WU0_PIN == gpio->pin) {
em4_int_no = 0;
#endif
#if defined(GPIO_EM4WU1_PORT)
} else if (GPIO_EM4WU1_PORT == gpio->port && GPIO_EM4WU1_PIN == gpio->pin) {
em4_int_no = 1;
#endif
#if defined(GPIO_EM4WU3_PORT)
} else if (GPIO_EM4WU3_PORT == gpio->port && GPIO_EM4WU3_PIN == gpio->pin) {
em4_int_no = 3;
#endif
#if defined(GPIO_EM4WU4_PORT)
} else if (GPIO_EM4WU4_PORT == gpio->port && GPIO_EM4WU4_PIN == gpio->pin) {
em4_int_no = 4;
#endif
#if defined(GPIO_EM4WU6_PORT)
} else if (GPIO_EM4WU6_PORT == gpio->port && GPIO_EM4WU6_PIN == gpio->pin) {
em4_int_no = 6;
#endif
#if defined(GPIO_EM4WU7_PORT)
} else if (GPIO_EM4WU7_PORT == gpio->port && GPIO_EM4WU7_PIN == gpio->pin) {
em4_int_no = 7;
#endif
#if defined(GPIO_EM4WU8_PORT)
} else if (GPIO_EM4WU8_PORT == gpio->port && GPIO_EM4WU8_PIN == gpio->pin) {
em4_int_no = 8;
#endif
#if defined(GPIO_EM4WU9_PORT)
} else if (GPIO_EM4WU9_PORT == gpio->port && GPIO_EM4WU9_PIN == gpio->pin) {
em4_int_no = 9;
#endif
#if defined(GPIO_EM4WU10_PORT)
} else if (GPIO_EM4WU10_PORT == gpio->port && GPIO_EM4WU10_PIN == gpio->pin) {
em4_int_no = 10;
#endif
} else {
em4_int_no = -1;
}
return em4_int_no;
}
/*************************************************************************//**
* Disable GPIO pin wake-up from EM4.
*
* @param[in] pinmask Bit mask containing the bitwise logic OR of which GPIO pin(s) to disable.
*****************************************************************************/
__INLINE void sl_hal_gpio_disable_pin_em4_wakeup(uint32_t pinmask)
{
EFM_ASSERT((pinmask & ~_GPIO_EM4WUEN_MASK) == 0UL);
GPIO->EM4WUEN &= ~pinmask;
}
/**************************************************************************//**
* Enable GPIO pin retention of output enable, output value, pull enable, and
* pull direction in EM4.
*
* @note The behavior of this function depends on the configured GPIO retention mode.
* If the GPIO retention mode is configured to be "SWUNLATCH" then this
* function will not change anything. If the retention mode is anything else
* then this function will set the GPIO retention mode to "EM4EXIT" when the
* enable argument is true, and "Disabled" when false.
*
* @param[in] enable true - enable EM4 pin retention.
* false - disable EM4 pin retention.
*****************************************************************************/
__INLINE void sl_hal_gpio_set_pin_em4_retention(bool enable)
{
// Leave configuration alone when software unlatch is used.
uint32_t mode = EMU->EM4CTRL & _EMU_EM4CTRL_EM4IORETMODE_MASK;
if (mode == EMU_EM4CTRL_EM4IORETMODE_SWUNLATCH) {
return;
}
if (enable) {
EMU->EM4CTRL = (EMU->EM4CTRL & ~_EMU_EM4CTRL_EM4IORETMODE_MASK)
| EMU_EM4CTRL_EM4IORETMODE_EM4EXIT;
} else {
EMU->EM4CTRL = (EMU->EM4CTRL & ~_EMU_EM4CTRL_EM4IORETMODE_MASK)
| EMU_EM4CTRL_EM4IORETMODE_DISABLE;
}
}
/**************************************************************************//**
* Check which GPIO pin(s) that caused a wake-up from EM4.
*
* @return Bit mask containing the bitwise logic OR of which GPIO pin(s) caused the wake-up.
*****************************************************************************/
__INLINE uint32_t sl_hal_gpio_get_pin_em4_wakeup_cause(void)
{
return GPIO->IF & _GPIO_EM4WUEN_EM4WUEN_MASK;
}
/***************************************************************************//**
* Enable/Disable serial wire output pin.
*
* @note Enabling this pin is not sufficient to fully enable serial wire output,
* which is also dependent on issues outside the GPIO module.
* @note If debug port is locked, SWO pin is not disabled automatically. To avoid
* information leakage through SWO, disable SWO pin after locking debug port.
*
* @param[in] enable false - disable serial wire viewer pin (default after reset).
* true - enable serial wire viewer pin.
******************************************************************************/
__INLINE void sl_hal_gpio_enable_debug_swo(bool enable)
{
uint32_t bit = enable ? 0x1UL : 0x0UL;
if (bit != 0U) {
GPIO->TRACEROUTEPEN_SET = 1UL << _GPIO_TRACEROUTEPEN_SWVPEN_SHIFT;
} else {
GPIO->TRACEROUTEPEN_CLR = 1UL << _GPIO_TRACEROUTEPEN_SWVPEN_SHIFT;
}
}
/***************************************************************************//**
* Enable/disable serial wire clock pin.
*
* @note Disabling SWDClk will disable the debug interface, which may result in
* a lockout if done early in startup (before debugger is able to halt core).
*
* @param[in] enable false - disable serial wire clock.
* true - enable serial wire clock (default after reset).
******************************************************************************/
__INLINE void sl_hal_gpio_enable_debug_swd_clk(bool enable)
{
uint32_t bit = enable ? 0x1UL : 0x0UL;
if (bit != 0U) {
GPIO->DBGROUTEPEN_SET = 1UL << _GPIO_DBGROUTEPEN_SWCLKTCKPEN_SHIFT;
} else {
GPIO->DBGROUTEPEN_CLR = 1UL << _GPIO_DBGROUTEPEN_SWCLKTCKPEN_SHIFT;
}
}
/***************************************************************************//**
* Enable/disable serial wire data I/O pin.
*
* @note Disabling SWDClk will disable the debug interface, which may result in
* a lockout if done early in startup (before debugger is able to halt core).
*
* @param[in] enable false - disable serial wire data pin.
* true - enable serial wire data pin (default after reset).
******************************************************************************/
__INLINE void sl_hal_gpio_enable_debug_swd_io(bool enable)
{
uint32_t bit = enable ? 0x1UL : 0x0UL;
if (bit != 0U) {
GPIO->DBGROUTEPEN_SET = 1UL << _GPIO_DBGROUTEPEN_SWDIOTMSPEN_SHIFT;
} else {
GPIO->DBGROUTEPEN_CLR = 1UL << _GPIO_DBGROUTEPEN_SWDIOTMSPEN_SHIFT;
}
}
/** @} (end addtogroup gpio) */
#ifdef __cplusplus
}
#endif
#endif /* GPIO_PRESENT */
#endif /* SL_HAL_GPIO_H */

View File

@@ -0,0 +1,89 @@
/***************************************************************************//**
* @file
* @brief API defining access to SYSCFG registers
*******************************************************************************
* # License
* <b>Copyright 2023 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* 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.
*
******************************************************************************/
#ifndef SL_HAL_SYSCFG_H
#define SL_HAL_SYSCFG_H
#include <stdint.h>
#if defined(SL_TRUSTZONE_NONSECURE)
#include "sli_tz_service_syscfg.h"
#endif
#ifdef __cplusplus
extern "C" {
#endif
/***************************************************************************//**
* @addtogroup syscfg SYSTEM CONFIGURATION - System Configurations
* @brief Syscfg API
* @details
*
* @{
******************************************************************************/
/*******************************************************************************
********************************* DEFINES *********************************
******************************************************************************/
/*******************************************************************************
******************************** ENUMS ************************************
******************************************************************************/
/*******************************************************************************
******************************* STRUCTS ***********************************
******************************************************************************/
/*******************************************************************************
******************************** TZ SERVICES **********************************
******************************************************************************/
/*******************************************************************************
* @brief
* Reads CHIPREV register.
******************************************************************************/
uint32_t sl_hal_syscfg_read_chip_rev(void);
/*******************************************************************************
* @brief
* Set SYSTICEXTCLKEN bit in CFGSYSTIC to one.
******************************************************************************/
void sl_hal_syscfg_set_systicextclken_cfgsystic(void);
/*******************************************************************************
* @brief
* Clear SYSTICEXTCLKEN bit in CFGSYSTIC to zero.
******************************************************************************/
void sl_hal_syscfg_clear_systicextclken_cfgsystic(void);
#ifdef __cplusplus
}
#endif
#endif // SL_HAL_SYSCFG_H

View File

@@ -0,0 +1,445 @@
/***************************************************************************//**
* @file
* @brief System Real Time Counter (SYSRTC) peripheral API
*******************************************************************************
* # License
* <b>Copyright 2024 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* 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.
*
******************************************************************************/
#ifndef SL_HAL_SYSRTC_H
#define SL_HAL_SYSRTC_H
#include "em_device.h"
#if defined(SYSRTC_COUNT) && (SYSRTC_COUNT > 0)
#include <stdbool.h>
#include "sl_code_classification.h"
#ifdef __cplusplus
extern "C" {
#endif
#include <stdbool.h>
#include "sl_hal_sysrtc_compat.h"
#include "sl_enum.h"
/***************************************************************************//**
* @addtogroup sysrtc
* @{
******************************************************************************/
/*******************************************************************************
******************************* DEFINES ***********************************
******************************************************************************/
/// Minimum compare channels for SYSRTC group.
#define SYSRTC_GROUP_MIN_CHANNEL_COMPARE 1u
/// Maximum compare channels for SYSRTC group.
#define SYSRTC_GROUP_MAX_CHANNEL_COMPARE 2u
/// Minimum capture channels for SYSRTC group.
#define SYSRTC_GROUP_MIN_CHANNEL_CAPTURE 0u
/// Maximum capture channels for SYSRTC group.
#define SYSRTC_GROUP_MAX_CHANNEL_CAPTURE 1u
/// Sysrtc group number.
#if !defined(SYSRTC_GROUP_NUMBER)
#define SYSRTC_GROUP_NUMBER 1u
#endif
/// Validation of valid SYSRTC group for assert statements.
#define SYSRTC_GROUP_VALID(group) ((unsigned)(group) < SYSRTC_GROUP_NUMBER)
/*******************************************************************************
********************************* ENUM ************************************
******************************************************************************/
/// Capture input edge select.
SL_ENUM(sl_hal_sysrtc_capture_edge_t) {
SL_HAL_SYSRTC_CAPTURE_EDGE_RISING = 0, ///< Rising edges detected.
SL_HAL_SYSRTC_CAPTURE_EDGE_FALLING, ///< Falling edges detected.
SL_HAL_SYSRTC_CAPTURE_EDGE_BOTH ///< Both edges detected.
};
/// Compare match output action mode.
SL_ENUM(sl_hal_sysrtc_compare_match_out_action_t) {
SL_HAL_SYSRTC_COMPARE_MATCH_OUT_ACTION_CLEAR = 0, ///< Clear output.
SL_HAL_SYSRTC_COMPARE_MATCH_OUT_ACTION_SET, ///< Set output.
SL_HAL_SYSRTC_COMPARE_MATCH_OUT_ACTION_PULSE, ///< Generate a pulse.
SL_HAL_SYSRTC_COMPARE_MATCH_OUT_ACTION_TOGGLE, ///< Toggle output.
SL_HAL_SYSRTC_COMPARE_MATCH_OUT_ACTION_CMPIF ///< Export CMPIF.
};
/*******************************************************************************
******************************* STRUCTS ***********************************
******************************************************************************/
/// SYSRTC configuration structure.
typedef struct {
bool enable_debug_run; ///< Counter shall keep running during debug halt.
} sl_hal_sysrtc_config_t;
/// Suggested default values for SYSRTC configuration structure.
#define SYSRTC_CONFIG_DEFAULT \
{ \
false, /* Disable updating during debug halt. */ \
}
/// Compare channel configuration structure.
typedef struct {
sl_hal_sysrtc_compare_match_out_action_t compare_match_out_action; ///< Compare mode channel match output action.
} sl_hal_sysrtc_group_channel_compare_config_t;
/// Capture channel configuration structure.
typedef struct {
sl_hal_sysrtc_capture_edge_t capture_input_edge; ///< Capture mode channel input edge.
} sl_hal_sysrtc_group_channel_capture_config_t;
/// Group configuration structure.
typedef struct {
bool compare_channel0_enable; ///< Enable/Disable compare channel 0
bool compare_channel1_enable; ///< Enable/Disable compare channel 1
bool capture_channel0_enable; ///< Enable/Disable capture channel 0
sl_hal_sysrtc_group_channel_compare_config_t const *p_compare_channel0_config; ///< Pointer to compare channel 0 config
sl_hal_sysrtc_group_channel_compare_config_t const *p_compare_channel1_config; ///< Pointer to compare channel 1 config
sl_hal_sysrtc_group_channel_capture_config_t const *p_capture_channel0_config; ///< Pointer to capture channel 0 config
} sl_hal_sysrtc_group_config_t;
/// Suggested default values for compare channel configuration structure.
#define SYSRTC_GROUP_CHANNEL_COMPARE_CONFIG_DEFAULT \
{ \
SL_HAL_SYSRTC_COMPARE_MATCH_OUT_ACTION_PULSE \
}
/// Compare channel configuration for starting HFXO using PRS.
#define SYSRTC_GROUP_CHANNEL_COMPARE_CONFIG_EARLY_WAKEUP \
{ \
SL_HAL_SYSRTC_COMPARE_MATCH_OUT_ACTION_CMPIF \
}
/// Suggested default values for capture channel configuration structure.
#define SYSRTC_GROUP_CHANNEL_CAPTURE_CONFIG_DEFAULT \
{ \
SL_HAL_SYSRTC_CAPTURE_EDGE_RISING \
}
/// Suggested default values for SYSRTC group configuration structure.
#define SYSRTC_GROUP_CONFIG_DEFAULT \
{ \
true, /* Enable compare channel 0. */ \
false, /* Disable compare channel 1. */ \
false, /* Disable capture channel 0. */ \
NULL, /* NULL Pointer to configuration structure for compare channel 0*/ \
NULL, /* NULL Pointer to configuration structure for compare channel 1*/ \
NULL /* NULL Pointer to configuration structure for capture channel 0*/ \
}
/*******************************************************************************
***************************** PROTOTYPES **********************************
******************************************************************************/
/***************************************************************************//**
* Initializes SYSRTC module.
*
* Note that the compare values must be set separately with
* (sl_hal_sysrtc_set_group_compare_channel_value()), which should probably be
* done prior to the use of this function if configuring the SYSRTC to start
* when initialization is completed.
*
* @param[in] p_config A pointer to the SYSRTC initialization structure
* variable.
******************************************************************************/
void sl_hal_sysrtc_init(const sl_hal_sysrtc_config_t *p_config);
/***************************************************************************//**
* Enables SYSRTC counting.
******************************************************************************/
void sl_hal_sysrtc_enable(void);
/***************************************************************************//**
* Disables SYSRTC counting.
******************************************************************************/
void sl_hal_sysrtc_disable(void);
/***************************************************************************//**
* Waits for the SYSRTC to complete all synchronization of register changes
* and commands.
******************************************************************************/
SL_CODE_CLASSIFY(SL_CODE_COMPONENT_HAL_SYSRTC, SL_CODE_CLASS_TIME_CRITICAL)
__INLINE void sl_hal_sysrtc_wait_sync(void)
{
while ((SYSRTC0->EN & SYSRTC_EN_EN) && (SYSRTC0->SYNCBUSY != 0U)) {
// Wait for all synchronizations to finish
}
}
/***************************************************************************//**
* Waits for the SYSRTC to complete reseting or disabling procedure.
******************************************************************************/
__INLINE void sl_hal_sysrtc_wait_ready(void)
{
while ((SYSRTC0->SWRST & _SYSRTC_SWRST_RESETTING_MASK) || (SYSRTC0->EN & _SYSRTC_EN_DISABLING_MASK) || (SYSRTC0->SYNCBUSY != 0U)) {
// Wait for all synchronizations to finish
}
}
/***************************************************************************//**
* Starts SYSRTC counter.
*
* This function will send a start command to the SYSRTC peripheral. The SYSRTC
* peripheral will use some LF clock ticks before the command is executed.
* The sl_hal_sysrtc_wait_sync() function can be used to wait for the start
* command to be executed.
*
* @note This function requires the SYSRTC to be enabled.
******************************************************************************/
__INLINE void sl_hal_sysrtc_start(void)
{
sl_hal_sysrtc_wait_sync();
SYSRTC0->CMD = SYSRTC_CMD_START;
}
/***************************************************************************//**
* Stops the SYSRTC counter.
*
* This function will send a stop command to the SYSRTC peripheral. The SYSRTC
* peripheral will use some LF clock ticks before the command is executed.
* The sl_hal_sysrtc_wait_sync() function can be used to wait for the stop
* command to be executed.
*
* @note This function requires the SYSRTC to be enabled.
******************************************************************************/
__INLINE void sl_hal_sysrtc_stop(void)
{
sl_hal_sysrtc_wait_sync();
SYSRTC0->CMD = SYSRTC_CMD_STOP;
}
/***************************************************************************//**
* Restores SYSRTC to its reset state.
******************************************************************************/
void sl_hal_sysrtc_reset(void);
/***************************************************************************//**
* Gets SYSRTC STATUS register value.
*
* @return Current STATUS register value.
******************************************************************************/
__INLINE uint32_t sl_hal_sysrtc_get_status(void)
{
return SYSRTC0->STATUS;
}
/***************************************************************************//**
* Locks SYSRTC registers.
*
* @note When SYSRTC registers are locked SYSRTC_EN, SYSRTC_CFG, SYSRTC_CMD,
* SYSRTC_SWRST, SYSRTC_CNT and SYSRTC_TOPCNT registers cannot be written
* to.
******************************************************************************/
__INLINE void sl_hal_sysrtc_lock(void)
{
SYSRTC0->LOCK = ~SYSRTC_LOCK_LOCKKEY_UNLOCK;
}
/***************************************************************************//**
* Unlocks SYSRTC registers.
*
* @note When SYSRTC registers are locked SYSRTC_EN, SYSRTC_CFG, SYSRTC_CMD,
* SYSRTC_SWRST, SYSRTC_CNT and SYSRTC_TOPCNT registers cannot be written
* to.
******************************************************************************/
__INLINE void sl_hal_sysrtc_unlock(void)
{
SYSRTC0->LOCK = SYSRTC_LOCK_LOCKKEY_UNLOCK;
}
/***************************************************************************//**
* Gets SYSRTC counter value.
*
* @return Current SYSRTC counter value.
******************************************************************************/
SL_CODE_CLASSIFY(SL_CODE_COMPONENT_HAL_SYSRTC, SL_CODE_CLASS_TIME_CRITICAL)
__INLINE uint32_t sl_hal_sysrtc_get_counter(void)
{
// Wait for Counter to synchronize before getting value
sl_hal_sysrtc_wait_sync();
return SYSRTC0->CNT;
}
/***************************************************************************//**
* Sets the SYSRTC counter value.
*
* @param[in] value The new SYSRTC counter value.
******************************************************************************/
__INLINE void sl_hal_sysrtc_set_counter(uint32_t value)
{
// Wait for Counter to synchronize before getting value
sl_hal_sysrtc_wait_sync();
SYSRTC0->CNT = value;
}
/***************************************************************************//**
* Initializes the selected SYSRTC group.
*
* @param[in] group_number SYSRTC group number to use.
*
* @param[in] p_group_config Pointer to group configuration structure
* variable.
******************************************************************************/
void sl_hal_sysrtc_init_group(uint8_t group_number,
sl_hal_sysrtc_group_config_t const *p_group_config);
/***************************************************************************//**
* Enables one or more SYSRTC interrupts for the given group.
*
* @note Depending on the use, a pending interrupt may already be set prior to
* enabling the interrupt. To ignore a pending interrupt, consider using
* sl_hal_sysrtc_clear_group_interrupts() prior to enabling the interrupt.
*
* @param[in] group_number SYSRTC group number to use.
*
* @param[in] flags SYSRTC interrupt sources to enable.
* Use a set of interrupt flags OR-ed together to set
* multiple interrupt sources for the given SYSRTC group.
******************************************************************************/
SL_CODE_CLASSIFY(SL_CODE_COMPONENT_HAL_SYSRTC, SL_CODE_CLASS_TIME_CRITICAL)
void sl_hal_sysrtc_enable_group_interrupts(uint8_t group_number,
uint32_t flags);
/***************************************************************************//**
* Disables one or more SYSRTC interrupts for the given group.
*
* @param[in] group_number SYSRTC group number to use.
*
* @param[in] flags SYSRTC interrupt sources to disable.
* Use a set of interrupt flags OR-ed together to disable
* multiple interrupt sources for the given SYSRTC group.
******************************************************************************/
SL_CODE_CLASSIFY(SL_CODE_COMPONENT_HAL_SYSRTC, SL_CODE_CLASS_TIME_CRITICAL)
void sl_hal_sysrtc_disable_group_interrupts(uint8_t group_number,
uint32_t flags);
/***************************************************************************//**
* Clears one or more pending SYSRTC interrupts for the given group.
*
* @param[in] group_number SYSRTC group number to use.
*
* @param[in] flags SYSRTC interrupt sources to clear.
* Use a set of interrupt flags OR-ed together to clear
* multiple interrupt sources for the given SYSRTC group.
******************************************************************************/
SL_CODE_CLASSIFY(SL_CODE_COMPONENT_HAL_SYSRTC, SL_CODE_CLASS_TIME_CRITICAL)
void sl_hal_sysrtc_clear_group_interrupts(uint8_t group_number,
uint32_t flags);
/***************************************************************************//**
* Gets pending SYSRTC interrupt flags for the given group.
*
* @note Event bits are not cleared by using this function.
*
* @param[in] group_number SYSRTC group number to use.
*
* @return Pending SYSRTC interrupt sources.
* Returns a set of interrupt flags OR-ed together for multiple
* interrupt sources in the SYSRTC group.
******************************************************************************/
SL_CODE_CLASSIFY(SL_CODE_COMPONENT_HAL_SYSRTC, SL_CODE_CLASS_TIME_CRITICAL)
uint32_t sl_hal_sysrtc_get_group_interrupts(uint8_t group_number);
/***************************************************************************//**
* Gets enabled and pending SYSRTC interrupt flags.
* Useful for handling more interrupt sources in the same interrupt handler.
*
* @note Interrupt flags are not cleared by using this function.
*
* @param[in] group_number SYSRTC group number to use.
*
* @return Pending and enabled SYSRTC interrupt sources.
* The return value is the bitwise AND of
* - the enabled interrupt sources in SYSRTC_GRPx_IEN and
* - the pending interrupt flags SYSRTC_GRPx_IF.
******************************************************************************/
uint32_t sl_hal_sysrtc_get_group_enabled_interrupts(uint8_t group_number);
/***************************************************************************//**
* Sets one or more pending SYSRTC interrupts for the given group from Software.
*
* @param[in] group_number SYSRTC group number to use.
*
* @param[in] flags SYSRTC interrupt sources to set to pending.
* Use a set of interrupt flags OR-ed together to set
* multiple interrupt sources for the SYSRTC group.
******************************************************************************/
void sl_hal_sysrtc_set_group_interrupts(uint8_t group_number,
uint32_t flags);
/***************************************************************************//**
* Gets SYSRTC compare register value for selected channel of given group.
*
* @param[in] group_number SYSRTC group number to use.
*
* @param[in] channel Channel selector.
*
* @return Compare register value.
******************************************************************************/
SL_CODE_CLASSIFY(SL_CODE_COMPONENT_HAL_SYSRTC, SL_CODE_CLASS_TIME_CRITICAL)
uint32_t sl_hal_sysrtc_get_group_compare_channel_value(uint8_t group_number,
uint8_t channel);
/***************************************************************************//**
* Sets SYSRTC compare register value for selected channel of given group.
*
* @param[in] group_number SYSRTC group number to use.
*
* @param[in] channel Channel selector.
*
* @param[in] value Compare register value.
******************************************************************************/
SL_CODE_CLASSIFY(SL_CODE_COMPONENT_HAL_SYSRTC, SL_CODE_CLASS_TIME_CRITICAL)
void sl_hal_sysrtc_set_group_compare_channel_value(uint8_t group_number,
uint8_t channel,
uint32_t value);
/***************************************************************************//**
* Gets SYSRTC input capture register value for capture channel of given group.
*
* @param[in] group_number SYSRTC group number to use.
*
* @return Capture register value.
******************************************************************************/
SL_CODE_CLASSIFY(SL_CODE_COMPONENT_HAL_SYSRTC, SL_CODE_CLASS_TIME_CRITICAL)
uint32_t sl_hal_sysrtc_get_group_capture_channel_value(uint8_t group_number);
/** @} (end addtogroup sysrtc) */
#ifdef __cplusplus
}
#endif
#endif /* defined(SYSRTC_COUNT) && (SYSRTC_COUNT > 0) */
#endif /* SL_HAL_SYSRTC_H */

View File

@@ -0,0 +1,89 @@
/***************************************************************************//**
* @file
* @brief SYSRTC Compatibility Layer.
*******************************************************************************
* # License
* <b>Copyright 2024 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* 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.
*
******************************************************************************/
#ifndef SL_HAL_SYSRTC_COMPAT_H
#define SL_HAL_SYSRTC_COMPAT_H
#ifdef __cplusplus
extern "C" {
#endif
/*******************************************************************************
********************************* DEFINES *********************************
******************************************************************************/
// Enum.
#define SL_SYSRTC_CAPTURE_EDGE_RISING SL_HAL_SYSRTC_CAPTURE_EDGE_RISING
#define SL_SYSRTC_CAPTURE_EDGE_FALLING SL_HAL_SYSRTC_CAPTURE_EDGE_FALLING
#define SL_SYSRTC_CAPTURE_EDGE_BOTH SL_HAL_SYSRTC_CAPTURE_EDGE_BOTH
#define SL_SYSRTC_COMPARE_MATCH_OUT_ACTION_CLEAR SL_HAL_SYSRTC_COMPARE_MATCH_OUT_ACTION_CLEAR
#define SL_SYSRTC_COMPARE_MATCH_OUT_ACTION_SET SL_HAL_SYSRTC_COMPARE_MATCH_OUT_ACTION_SET
#define SL_SYSRTC_COMPARE_MATCH_OUT_ACTION_PULSE SL_HAL_SYSRTC_COMPARE_MATCH_OUT_ACTION_PULSE
#define SL_SYSRTC_COMPARE_MATCH_OUT_ACTION_TOGGLE SL_HAL_SYSRTC_COMPARE_MATCH_OUT_ACTION_TOGGLE
#define SL_SYSRTC_COMPARE_MATCH_OUT_ACTION_CMPIF SL_HAL_SYSRTC_COMPARE_MATCH_OUT_ACTION_CMPIF
#define sl_sysrtc_capture_edge_t sl_hal_sysrtc_capture_edge_t
#define sl_sysrtc_compare_match_out_action_t sl_hal_sysrtc_compare_match_out_action_t
// Structure.
#define sl_sysrtc_config_t sl_hal_sysrtc_config_t
#define sl_sysrtc_group_channel_compare_config_t sl_hal_sysrtc_group_channel_compare_config_t
#define sl_sysrtc_group_channel_capture_config_t sl_hal_sysrtc_group_channel_capture_config_t
#define sl_sysrtc_group_config_t sl_hal_sysrtc_group_config_t
// Function.
#define sl_sysrtc_init sl_hal_sysrtc_init
#define sl_sysrtc_enable sl_hal_sysrtc_enable
#define sl_sysrtc_disable sl_hal_sysrtc_disable
#define sl_sysrtc_wait_sync sl_hal_sysrtc_wait_sync
#define sl_sysrtc_wait_ready sl_hal_sysrtc_wait_ready
#define sl_sysrtc_start sl_hal_sysrtc_start
#define sl_sysrtc_stop sl_hal_sysrtc_stop
#define sl_sysrtc_reset sl_hal_sysrtc_reset
#define sl_sysrtc_get_status sl_hal_sysrtc_get_status
#define sl_sysrtc_lock sl_hal_sysrtc_lock
#define sl_sysrtc_unlock sl_hal_sysrtc_unlock
#define sl_sysrtc_get_counter sl_hal_sysrtc_get_counter
#define sl_sysrtc_set_counter sl_hal_sysrtc_set_counter
#define sl_sysrtc_init_group sl_hal_sysrtc_init_group
#define sl_sysrtc_enable_group_interrupts sl_hal_sysrtc_enable_group_interrupts
#define sl_sysrtc_disable_group_interrupts sl_hal_sysrtc_disable_group_interrupts
#define sl_sysrtc_clear_group_interrupts sl_hal_sysrtc_clear_group_interrupts
#define sl_sysrtc_get_group_interrupts sl_hal_sysrtc_get_group_interrupts
#define sl_sysrtc_get_group_enabled_interrupts sl_hal_sysrtc_get_group_enabled_interrupts
#define sl_sysrtc_set_group_interrupts sl_hal_sysrtc_set_group_interrupts
#define sl_sysrtc_get_group_compare_channel_value sl_hal_sysrtc_get_group_compare_channel_value
#define sl_sysrtc_set_group_compare_channel_value sl_hal_sysrtc_set_group_compare_channel_value
#define sl_sysrtc_get_group_capture_channel_value sl_hal_sysrtc_get_group_capture_channel_value
#ifdef __cplusplus
}
#endif
#endif // SL_HAL_SYSRTC_COMPAT_H

View File

@@ -0,0 +1,146 @@
/***************************************************************************//**
* @file
* @brief System API
*******************************************************************************
* # License
* <b>Copyright 2024 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* 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.
*
******************************************************************************/
#ifndef _SL_HAL_SYSTEM_H
#define _SL_HAL_SYSTEM_H
#include "em_device.h"
#include "sl_hal_system_generic.h"
#include "sl_enum.h"
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/***************************************************************************//**
* @addtogroup system SYSTEM - System Utils
* @brief System API
* @details
* This module contains functions to read information such as RAM and Flash size,
* device unique ID, chip revision, family, and part number from DEVINFO and
* SCB blocks. Functions to configure and read status from FPU are available for
* compatible devices.
* @{
******************************************************************************/
/*******************************************************************************
******************************** ENUMS ************************************
******************************************************************************/
/// Family identifiers.
SL_ENUM_GENERIC(sl_hal_system_part_family_t, uint32_t) {
#if defined(_SILICON_LABS_32B_SERIES_2_CONFIG_1)
SL_HAL_SYSTEM_PART_FAMILY_MIGHTY_21 = DEVINFO_PART_FAMILY_MG | (21 << _DEVINFO_PART_FAMILYNUM_SHIFT), ///< EFR32 Mighty Gecko Series 2 Config 1 Value Device Family
SL_HAL_SYSTEM_PART_FAMILY_FLEX_21 = DEVINFO_PART_FAMILY_FG | (21 << _DEVINFO_PART_FAMILYNUM_SHIFT), ///< EFR32 Flex Gecko Series 2 Config 1 Value Device Family
SL_HAL_SYSTEM_PART_FAMILY_BLUE_21 = DEVINFO_PART_FAMILY_BG | (21 << _DEVINFO_PART_FAMILYNUM_SHIFT), ///< EFR32 Blue Gecko Series 2 Config 1 Value Device Family
SL_HAL_SYSTEM_PART_FAMILY_MIGHTY_RCP_21 = DEVINFO_PART_FAMILY_MR | (21 << _DEVINFO_PART_FAMILYNUM_SHIFT), ///< EFR32 Mighty RCP Series 2 Config 1 Value Device Family
#endif
#if defined(_SILICON_LABS_32B_SERIES_2_CONFIG_2)
SL_HAL_SYSTEM_PART_FAMILY_MIGHTY_22 = DEVINFO_PART_FAMILY_MG | (22 << _DEVINFO_PART_FAMILYNUM_SHIFT), ///< EFR32 Mighty Gecko Series 2 Config 2 Value Device Family
SL_HAL_SYSTEM_PART_FAMILY_FLEX_22 = DEVINFO_PART_FAMILY_FG | (22 << _DEVINFO_PART_FAMILYNUM_SHIFT), ///< EFR32 Flex Gecko Series 2 Config 2 Value Device Family
SL_HAL_SYSTEM_PART_FAMILY_BLUE_22 = DEVINFO_PART_FAMILY_BG | (22 << _DEVINFO_PART_FAMILYNUM_SHIFT), ///< EFR32 Blue Gecko Series 2 Config 2 Value Device Family
SL_HAL_SYSTEM_PART_FAMILY_EFM32_PEARL_22 = DEVINFO_PART_FAMILY_PG | (22 << _DEVINFO_PART_FAMILYNUM_SHIFT), ///< EFM32 Pearl Gecko Series 2 Config 2 Value Device Family
#endif
#if defined(_SILICON_LABS_32B_SERIES_2_CONFIG_3)
SL_HAL_SYSTEM_PART_FAMILY_FLEX_23 = DEVINFO_PART_FAMILY_FG | (23 << _DEVINFO_PART_FAMILYNUM_SHIFT), ///< EFR32 Flex Gecko Series 2 Config 3 Value Device Family
SL_HAL_SYSTEM_PART_FAMILY_ZEN_23 = DEVINFO_PART_FAMILY_ZG | (23 << _DEVINFO_PART_FAMILYNUM_SHIFT), ///< EFR32 Zen Gecko Series 2 Config 3 Value Device Family
SL_HAL_SYSTEM_PART_FAMILY_EFM32_PEARL_23 = DEVINFO_PART_FAMILY_PG | (23 << _DEVINFO_PART_FAMILYNUM_SHIFT), ///< EFM32 Pearl Gecko Series 2 Config 3 Value Device Family
SL_HAL_SYSTEM_PART_FAMILY_SIDEWALK_23 = DEVINFO_PART_FAMILY_SG | (23 << _DEVINFO_PART_FAMILYNUM_SHIFT), ///< EFR32 Side Walk Gecko Series 2 Config 3 Value Device Family
#endif
#if defined(_SILICON_LABS_32B_SERIES_2_CONFIG_4)
SL_HAL_SYSTEM_PART_FAMILY_MIGHTY_24 = DEVINFO_PART_FAMILY_MG | (24 << _DEVINFO_PART_FAMILYNUM_SHIFT), ///< EFR32 Mighty Gecko Series 2 Config 4 Value Device Family
SL_HAL_SYSTEM_PART_FAMILY_FLEX_24 = DEVINFO_PART_FAMILY_FG | (24 << _DEVINFO_PART_FAMILYNUM_SHIFT), ///< EFR32 Flex Gecko Series 2 Config 4 Value Device Family
SL_HAL_SYSTEM_PART_FAMILY_BLUE_24 = DEVINFO_PART_FAMILY_BG | (24 << _DEVINFO_PART_FAMILYNUM_SHIFT), ///< EFR32 Blue Gecko Series 2 Config 4 Value Device Family
#endif
#if defined(_SILICON_LABS_32B_SERIES_2_CONFIG_5)
SL_HAL_SYSTEM_PART_FAMILY_FLEX_25 = DEVINFO_PART_FAMILY_FG | (25 << _DEVINFO_PART_FAMILYNUM_SHIFT), ///< EFR32 Flex Gecko Series 2 Config 5 Value Device Family
#endif
#if defined(_SILICON_LABS_32B_SERIES_2_CONFIG_6)
SL_HAL_SYSTEM_PART_FAMILY_MIGHTY_26 = DEVINFO_PART_FAMILY_MG | (26 << _DEVINFO_PART_FAMILYNUM_SHIFT), ///< EFR32 Mighty Gecko Series 2 Config 6 Value Device Family
SL_HAL_SYSTEM_PART_FAMILY_BLUE_26 = DEVINFO_PART_FAMILY_BG | (26 << _DEVINFO_PART_FAMILYNUM_SHIFT), ///< EFR32 Blue Gecko Series 2 Config 6 Value Device Family
SL_HAL_SYSTEM_PART_FAMILY_EFM32_PEARL_26 = DEVINFO_PART_FAMILY_PG | (26 << _DEVINFO_PART_FAMILYNUM_SHIFT), ///< EFM32 Pearl Gecko Series 2 Config 6 Value Device Family
#endif
#if defined(_SILICON_LABS_32B_SERIES_2_CONFIG_7)
SL_HAL_SYSTEM_PART_FAMILY_MIGHTY_27 = DEVINFO_PART_FAMILY_MG | (27 << _DEVINFO_PART_FAMILYNUM_SHIFT), ///< EFR32 Mighty Gecko Series 2 Config 7 Value Device Family
SL_HAL_SYSTEM_PART_FAMILY_BLUE_27 = DEVINFO_PART_FAMILY_BG | (27 << _DEVINFO_PART_FAMILYNUM_SHIFT), ///< EFR32 Blue Gecko Series 2 Config 7 Value Device Family
#endif
#if defined(_SILICON_LABS_32B_SERIES_2_CONFIG_8)
SL_HAL_SYSTEM_PART_FAMILY_FLEX_28 = DEVINFO_PART_FAMILY_FG | (28 << _DEVINFO_PART_FAMILYNUM_SHIFT), ///< EFR32 Flex Gecko Series 2 Config 8 Value Device Family
SL_HAL_SYSTEM_PART_FAMILY_ZEN_28 = DEVINFO_PART_FAMILY_ZG | (28 << _DEVINFO_PART_FAMILYNUM_SHIFT), ///< EFR32 Zen Gecko Series 2 Config 8 Value Device Family
SL_HAL_SYSTEM_PART_FAMILY_SIDEWALK_28 = DEVINFO_PART_FAMILY_SG | (28 << _DEVINFO_PART_FAMILYNUM_SHIFT), ///< EFR32 Side Walk Gecko Series 2 Config 8 Value Device Family
SL_HAL_SYSTEM_PART_FAMILY_EFM32_PEARL_28 = DEVINFO_PART_FAMILY_PG | (28 << _DEVINFO_PART_FAMILYNUM_SHIFT), ///< EFM32 Pearl Gecko Series 2 Config 8 Value Device Family
#endif
#if defined(_SILICON_LABS_32B_SERIES_3_CONFIG_301)
SL_HAL_SYSTEM_PART_FAMILY_BLUETOOTH_301 = DEVINFO_PART0_PROTOCOL_BLUETOOTH \
| (0x33 << _DEVINFO_PART0_SERIES_SHIFT) \
| (0x30 << _DEVINFO_PART0_DIECODE0_SHIFT), ///< SI Series 3 Bluetooth Config 1 Value Device Family (BG)
SL_HAL_SYSTEM_PART_FAMILY_PROPRIETARY_301 = DEVINFO_PART0_PROTOCOL_PROPRIETARY \
| (0x33 << _DEVINFO_PART0_SERIES_SHIFT) \
| (0x30 << _DEVINFO_PART0_DIECODE0_SHIFT), ///< SI Series 3 Proprietary Config 1 Value Device Family (FG)
SL_HAL_SYSTEM_PART_FAMILY_FIFTEENPFOUR_301 = DEVINFO_PART0_PROTOCOL_FIFTEENPFOUR \
| (0x33 << _DEVINFO_PART0_SERIES_SHIFT) \
| (0x30 << _DEVINFO_PART0_DIECODE0_SHIFT), ///< SI Series 3 15.4 Config 1 Value Device Family (MG)
SL_HAL_SYSTEM_PART_FAMILY_PEARL_301 = DEVINFO_PART0_PROTOCOL_PEARL \
| (0x33 << _DEVINFO_PART0_SERIES_SHIFT) \
| (0x30 << _DEVINFO_PART0_DIECODE0_SHIFT), ///< SI Series 3 Pearl Config 1 Value Device Family (PG)
SL_HAL_SYSTEM_PART_FAMILY_WIFI_301 = DEVINFO_PART0_PROTOCOL_WIFI \
| (0x33 << _DEVINFO_PART0_SERIES_SHIFT) \
| (0x30 << _DEVINFO_PART0_DIECODE0_SHIFT), ///< SI Series 3 Wifi Config 1 Value Device Family (WG)
SL_HAL_SYSTEM_PART_FAMILY_ZWAVE_301 = DEVINFO_PART0_PROTOCOL_ZWAVE \
| (0x33 << _DEVINFO_PART0_SERIES_SHIFT) \
| (0x30 << _DEVINFO_PART0_DIECODE0_SHIFT), ///< SI Series 3 Zwave Config 1 Value Device Family (ZG)
#endif
SL_HAL_SYSTEM_PART_FAMILY_UNKNOWN = 0xFF ///< Unknown Device Family. Family ID is missing on unprogrammed parts.
};
/***************************************************************************//**
* @brief
* Get the MCU family identifier.
*
* @return
* Family identifier of MCU.
*
* @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 \<part_family\>_devinfo.h (refer to code
* below for details).
******************************************************************************/
sl_hal_system_part_family_t sl_hal_system_get_family(void);
/** @} (end addtogroup system) */
#ifdef __cplusplus
}
#endif
#endif /* #ifndef _SL_HAL_SYSTEM_H */

Some files were not shown because too many files have changed in this diff Show More