Initial commit of firmware
This commit is contained in:
1168
Libs/platform/emlib/inc/em_acmp.h
Normal file
1168
Libs/platform/emlib/inc/em_acmp.h
Normal file
File diff suppressed because it is too large
Load Diff
36
Libs/platform/emlib/inc/em_assert.h
Normal file
36
Libs/platform/emlib/inc/em_assert.h
Normal 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 */
|
||||
473
Libs/platform/emlib/inc/em_burtc.h
Normal file
473
Libs/platform/emlib/inc/em_burtc.h
Normal 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 */
|
||||
350
Libs/platform/emlib/inc/em_bus.h
Normal file
350
Libs/platform/emlib/inc/em_bus.h
Normal 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 */
|
||||
483
Libs/platform/emlib/inc/em_chip.h
Normal file
483
Libs/platform/emlib/inc/em_chip.h
Normal 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 */
|
||||
3655
Libs/platform/emlib/inc/em_cmu.h
Normal file
3655
Libs/platform/emlib/inc/em_cmu.h
Normal file
File diff suppressed because it is too large
Load Diff
184
Libs/platform/emlib/inc/em_cmu_compat.h
Normal file
184
Libs/platform/emlib/inc/em_cmu_compat.h
Normal 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
|
||||
36
Libs/platform/emlib/inc/em_common.h
Normal file
36
Libs/platform/emlib/inc/em_common.h
Normal 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 */
|
||||
174
Libs/platform/emlib/inc/em_core.h
Normal file
174
Libs/platform/emlib/inc/em_core.h
Normal 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 */
|
||||
36
Libs/platform/emlib/inc/em_core_generic.h
Normal file
36
Libs/platform/emlib/inc/em_core_generic.h
Normal 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 */
|
||||
130
Libs/platform/emlib/inc/em_dbg.h
Normal file
130
Libs/platform/emlib/inc/em_dbg.h
Normal 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 */
|
||||
1831
Libs/platform/emlib/inc/em_emu.h
Normal file
1831
Libs/platform/emlib/inc/em_emu.h
Normal file
File diff suppressed because it is too large
Load Diff
1223
Libs/platform/emlib/inc/em_eusart.h
Normal file
1223
Libs/platform/emlib/inc/em_eusart.h
Normal file
File diff suppressed because it is too large
Load Diff
218
Libs/platform/emlib/inc/em_eusart_compat.h
Normal file
218
Libs/platform/emlib/inc/em_eusart_compat.h
Normal 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
|
||||
346
Libs/platform/emlib/inc/em_gpcrc.h
Normal file
346
Libs/platform/emlib/inc/em_gpcrc.h
Normal 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 */
|
||||
1380
Libs/platform/emlib/inc/em_gpio.h
Normal file
1380
Libs/platform/emlib/inc/em_gpio.h
Normal file
File diff suppressed because it is too large
Load Diff
525
Libs/platform/emlib/inc/em_i2c.h
Normal file
525
Libs/platform/emlib/inc/em_i2c.h
Normal 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 */
|
||||
1407
Libs/platform/emlib/inc/em_iadc.h
Normal file
1407
Libs/platform/emlib/inc/em_iadc.h
Normal file
File diff suppressed because it is too large
Load Diff
2824
Libs/platform/emlib/inc/em_ldma.h
Normal file
2824
Libs/platform/emlib/inc/em_ldma.h
Normal file
File diff suppressed because it is too large
Load Diff
334
Libs/platform/emlib/inc/em_letimer.h
Normal file
334
Libs/platform/emlib/inc/em_letimer.h
Normal 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 */
|
||||
889
Libs/platform/emlib/inc/em_msc.h
Normal file
889
Libs/platform/emlib/inc/em_msc.h
Normal 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 */
|
||||
81
Libs/platform/emlib/inc/em_msc_compat.h
Normal file
81
Libs/platform/emlib/inc/em_msc_compat.h
Normal 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 */
|
||||
1459
Libs/platform/emlib/inc/em_opamp.h
Normal file
1459
Libs/platform/emlib/inc/em_opamp.h
Normal file
File diff suppressed because it is too large
Load Diff
905
Libs/platform/emlib/inc/em_pcnt.h
Normal file
905
Libs/platform/emlib/inc/em_pcnt.h
Normal 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 */
|
||||
1170
Libs/platform/emlib/inc/em_prs.h
Normal file
1170
Libs/platform/emlib/inc/em_prs.h
Normal file
File diff suppressed because it is too large
Load Diff
169
Libs/platform/emlib/inc/em_ramfunc.h
Normal file
169
Libs/platform/emlib/inc/em_ramfunc.h
Normal 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 */
|
||||
178
Libs/platform/emlib/inc/em_rmu.h
Normal file
178
Libs/platform/emlib/inc/em_rmu.h
Normal 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 */
|
||||
1762
Libs/platform/emlib/inc/em_smu.h
Normal file
1762
Libs/platform/emlib/inc/em_smu.h
Normal file
File diff suppressed because it is too large
Load Diff
174
Libs/platform/emlib/inc/em_syscfg.h
Normal file
174
Libs/platform/emlib/inc/em_syscfg.h
Normal 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
|
||||
365
Libs/platform/emlib/inc/em_system.h
Normal file
365
Libs/platform/emlib/inc/em_system.h
Normal 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 */
|
||||
91
Libs/platform/emlib/inc/em_system_generic.h
Normal file
91
Libs/platform/emlib/inc/em_system_generic.h
Normal 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 */
|
||||
1238
Libs/platform/emlib/inc/em_timer.h
Normal file
1238
Libs/platform/emlib/inc/em_timer.h
Normal file
File diff suppressed because it is too large
Load Diff
1093
Libs/platform/emlib/inc/em_usart.h
Normal file
1093
Libs/platform/emlib/inc/em_usart.h
Normal file
File diff suppressed because it is too large
Load Diff
773
Libs/platform/emlib/inc/em_vdac.h
Normal file
773
Libs/platform/emlib/inc/em_vdac.h
Normal 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 */
|
||||
68
Libs/platform/emlib/inc/em_version.h
Normal file
68
Libs/platform/emlib/inc/em_version.h
Normal 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 */
|
||||
455
Libs/platform/emlib/inc/em_wdog.h
Normal file
455
Libs/platform/emlib/inc/em_wdog.h
Normal 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 */
|
||||
1902
Libs/platform/emlib/inc/sli_em_cmu.h
Normal file
1902
Libs/platform/emlib/inc/sli_em_cmu.h
Normal file
File diff suppressed because it is too large
Load Diff
709
Libs/platform/emlib/src/em_acmp.c
Normal file
709
Libs/platform/emlib/src/em_acmp.c
Normal 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) */
|
||||
433
Libs/platform/emlib/src/em_burtc.c
Normal file
433
Libs/platform/emlib/src/em_burtc.c
Normal 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 */
|
||||
11864
Libs/platform/emlib/src/em_cmu.c
Normal file
11864
Libs/platform/emlib/src/em_cmu.c
Normal file
File diff suppressed because it is too large
Load Diff
518
Libs/platform/emlib/src/em_core.c
Normal file
518
Libs/platform/emlib/src/em_core.c
Normal 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) */
|
||||
132
Libs/platform/emlib/src/em_dbg.c
Normal file
132
Libs/platform/emlib/src/em_dbg.c
Normal 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 ) */
|
||||
4319
Libs/platform/emlib/src/em_emu.c
Normal file
4319
Libs/platform/emlib/src/em_emu.c
Normal file
File diff suppressed because it is too large
Load Diff
1398
Libs/platform/emlib/src/em_eusart.c
Normal file
1398
Libs/platform/emlib/src/em_eusart.c
Normal file
File diff suppressed because it is too large
Load Diff
138
Libs/platform/emlib/src/em_gpcrc.c
Normal file
138
Libs/platform/emlib/src/em_gpcrc.c
Normal 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) */
|
||||
452
Libs/platform/emlib/src/em_gpio.c
Normal file
452
Libs/platform/emlib/src/em_gpio.c
Normal 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) */
|
||||
940
Libs/platform/emlib/src/em_i2c.c
Normal file
940
Libs/platform/emlib/src/em_i2c.c
Normal 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) */
|
||||
1178
Libs/platform/emlib/src/em_iadc.c
Normal file
1178
Libs/platform/emlib/src/em_iadc.c
Normal file
File diff suppressed because it is too large
Load Diff
461
Libs/platform/emlib/src/em_ldma.c
Normal file
461
Libs/platform/emlib/src/em_ldma.c
Normal 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 ) */
|
||||
685
Libs/platform/emlib/src/em_letimer.c
Normal file
685
Libs/platform/emlib/src/em_letimer.c
Normal 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) */
|
||||
2081
Libs/platform/emlib/src/em_msc.c
Normal file
2081
Libs/platform/emlib/src/em_msc.c
Normal file
File diff suppressed because it is too large
Load Diff
700
Libs/platform/emlib/src/em_opamp.c
Normal file
700
Libs/platform/emlib/src/em_opamp.c
Normal 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) */
|
||||
1067
Libs/platform/emlib/src/em_pcnt.c
Normal file
1067
Libs/platform/emlib/src/em_pcnt.c
Normal file
File diff suppressed because it is too large
Load Diff
661
Libs/platform/emlib/src/em_prs.c
Normal file
661
Libs/platform/emlib/src/em_prs.c
Normal 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) */
|
||||
402
Libs/platform/emlib/src/em_rmu.c
Normal file
402
Libs/platform/emlib/src/em_rmu.c
Normal 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) */
|
||||
433
Libs/platform/emlib/src/em_system.c
Normal file
433
Libs/platform/emlib/src/em_system.c
Normal 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) */
|
||||
520
Libs/platform/emlib/src/em_timer.c
Normal file
520
Libs/platform/emlib/src/em_timer.c
Normal 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) */
|
||||
1444
Libs/platform/emlib/src/em_usart.c
Normal file
1444
Libs/platform/emlib/src/em_usart.c
Normal file
File diff suppressed because it is too large
Load Diff
636
Libs/platform/emlib/src/em_vdac.c
Normal file
636
Libs/platform/emlib/src/em_vdac.c
Normal 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) */
|
||||
355
Libs/platform/emlib/src/em_wdog.c
Normal file
355
Libs/platform/emlib/src/em_wdog.c
Normal 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) */
|
||||
Reference in New Issue
Block a user