Initial commit of firmware

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

View File

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

View File

@@ -0,0 +1,225 @@
/***************************************************************************//**
* @file
* @brief Simple Button Driver
*******************************************************************************
* # License
* <b>Copyright 2019 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* SPDX-License-Identifier: Zlib
*
* The licensor of this software is Silicon Laboratories Inc.
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*
******************************************************************************/
#ifndef SL_SIMPLE_BUTTON_H
#define SL_SIMPLE_BUTTON_H
#include "sl_button.h"
#include "sl_gpio.h"
#ifdef __cplusplus
extern "C" {
#endif
/***************************************************************************//**
* @addtogroup button
* @{
******************************************************************************/
/***************************************************************************//**
* @addtogroup simple_button Simple Button Driver
* @details Simple Button Driver module provides APIs to initalize and read
* simple buttons. Subsequent sections provide more insight into button
* driver configuration and usage.
* @{
******************************************************************************/
/*******************************************************************************
****************************** DEFINES ************************************
******************************************************************************/
#define SL_SIMPLE_BUTTON_MODE_POLL 0U ///< BUTTON input capture using polling
#define SL_SIMPLE_BUTTON_MODE_POLL_AND_DEBOUNCE 1U ///< BUTTON input capture using polling and debouncing
#define SL_SIMPLE_BUTTON_MODE_INTERRUPT 2U ///< BUTTON input capture using interrupt
#define SL_SIMPLE_BUTTON_DISABLED 2U ///< BUTTON state is disabled
#define SL_SIMPLE_BUTTON_PRESSED 1U ///< BUTTON state is pressed
#define SL_SIMPLE_BUTTON_RELEASED 0U ///< BUTTON state is released
#define SL_SIMPLE_BUTTON_GET_STATE(context) (((sl_simple_button_context_t *)(context))->state) ///< BUTTON member function to get state
#define SL_SIMPLE_BUTTON_GET_PORT(context) (((sl_simple_button_context_t *)(context))->port) ///< BUTTON member function to get port
#define SL_SIMPLE_BUTTON_GET_PIN(context) (((sl_simple_button_context_t *)(context))->pin) ///< BUTTON member function to get pin
#define SL_SIMPLE_BUTTON_GET_MODE(context) (((sl_simple_button_context_t *)(context))->mode) ///< BUTTON member function to get mode
/*******************************************************************************
***************************** DATA TYPES *********************************
******************************************************************************/
/// A Simple BUTTON instance
typedef struct {
sl_button_state_t state; ///< Current button state
uint16_t history; ///< History of button states
sl_gpio_port_t port; ///< Button port
uint8_t pin; ///< Button pin
sl_button_mode_t mode; ///< Mode of operation
} sl_simple_button_context_t;
/*******************************************************************************
***************************** PROTOTYPES **********************************
******************************************************************************/
/***************************************************************************//**
* Initialize the simple button driver.
*
* @param[in] handle Pointer to button handle:
* - sl_button_t
*
* @return Status Code:
* - SL_STATUS_OK
******************************************************************************/
sl_status_t sl_simple_button_init(const sl_button_t *handle);
/***************************************************************************//**
* Get the current state of the simple button.
*
* @param[in] handle Pointer to button handle:
* - sl_button_t
*
* @return Button State: Current state of the button
* - SL_SIMPLE_BUTTON_PRESSED
* - SL_SIMPLE_BUTTON_RELEASED
******************************************************************************/
sl_button_state_t sl_simple_button_get_state(const sl_button_t *handle);
/***************************************************************************//**
* Poll the simple button. (button mode - poll / poll and debonuce)
*
* @param[in] handle Pointer to button handle:
* - sl_button_t
******************************************************************************/
void sl_simple_button_poll_step(const sl_button_t *handle);
/***************************************************************************//**
* Enable the simple button.
*
* @param[in] handle Pointer to button handle:
* - sl_button_t
******************************************************************************/
void sl_simple_button_enable(const sl_button_t *handle);
/***************************************************************************//**
* Disable the simple button.
*
* @param[in] handle Pointer to button handle:
* - sl_button_t
******************************************************************************/
void sl_simple_button_disable(const sl_button_t *handle);
/** @} (end addtogroup simple_button) */
/** @} (end addtogroup button) */
// ******** THE REST OF THE FILE IS DOCUMENTATION ONLY !***********************
/// @addtogroup simple_button Simple Button Driver
/// @{
///
/// @details
///
///
/// @n @section simple_button_intro Introduction
///
/// The Simple Button driver is a module of the button driver that provides the functionality
/// to initialize and read simple buttons.
///
/// @n @section simple_button_config Simple Button Configuration
///
/// Simple buttons use the @ref sl_button_t struct and their @ref sl_simple_button_context_t
/// struct. These are automatically generated into the following files, as well as
/// instance specific headers with macro definitions in them. The samples below
/// are for a single instance called "inst0".
///
/// @code{.c}
///// sl_simple_button_instances.c
///
///#include "sl_simple_button.h"
///#include "sl_simple_button_inst0_config.h"
///
///sl_simple_button_context_t simple_inst0_context = {
/// .state = 0,
/// .history = 0,
/// .port = SL_SIMPLE_BUTTON_INST0_PORT,
/// .pin = SL_SIMPLE_BUTTON_INST0_PIN,
/// .mode = SL_SIMPLE_BUTTON_INST0_MODE,
///};
///
///const sl_button_t sl_button_inst0 = {
/// .context = &simple_inst0_context,
/// .init = sl_simple_button_init,
/// .get_state = sl_simple_button_get_state,
/// .poll = sl_simple_button_poll_step,
///};
///
///const sl_button_t *sl_simple_button_array[] = {&sl_button_inst0};
///const uint8_t simple_button_count = 1;
///
///void sl_simple_button_init_instances(void)
///{
/// sl_button_init(&sl_button_inst0);
///}
///
///void sl_simple_button_poll_instances(void)
///{
/// sl_button_poll_step(&sl_button_inst0);
///}
/// @endcode
///
/// @note The sl_simple_button_instances.c file is shown with only one instance, but if more
/// were in use they would all appear in this .c file.
///
/// @code{.c}
///// sl_simple_button_instances.h
///
///#ifndef SL_SIMPLE_BUTTON_INSTANCES_H
///#define SL_SIMPLE_BUTTON_INSTANCES_H
///
///#include "sl_simple_button.h"
///
///extern const sl_button_t sl_button_inst0;
///
///void sl_simple_button_init_instances(void);
///void sl_simple_button_poll_instances(void);
///
///#endif // SL_SIMPLE_BUTTON_INSTANCES_H
/// @endcode
///
/// @note The sl_simple_button_instances.h file is shown with only one instance, but if more
/// were in use they would all appear in this .h file.
///
/// @n @section simple_button_usage Simple Button Usage
///
/// The simple button driver has no differences in its usage from the common button driver.
/// See @ref buttondrv_usage.
///
/// @} end group simple_button ********************************************************/
#ifdef __cplusplus
}
#endif
#endif // SL_SIMPLE_BUTTON_H

View File

@@ -0,0 +1,76 @@
/***************************************************************************//**
* @file
* @brief Button Driver
*******************************************************************************
* # License
* <b>Copyright 2019 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* SPDX-License-Identifier: Zlib
*
* The licensor of this software is Silicon Laboratories Inc.
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*
******************************************************************************/
#include "sl_button.h"
#include <stddef.h>
sl_status_t sl_button_init(const sl_button_t *handle)
{
if (handle->init != NULL) {
return handle->init(handle);
} else {
return SL_STATUS_NULL_POINTER;
}
}
sl_button_state_t sl_button_get_state(const sl_button_t *handle)
{
if (handle->get_state != NULL) {
return handle->get_state(handle);
} else {
return (sl_button_state_t)BUTTON_ERROR;
}
}
void sl_button_poll_step(const sl_button_t *handle)
{
if (handle->poll != NULL) {
handle->poll(handle);
}
}
void sl_button_enable(const sl_button_t *handle)
{
if (handle->enable != NULL) {
handle->enable(handle);
}
}
void sl_button_disable(const sl_button_t *handle)
{
if (handle->disable != NULL) {
handle->disable(handle);
}
}
SL_WEAK void sl_button_on_change(const sl_button_t *handle)
{
(void)handle;
}

View File

@@ -0,0 +1,205 @@
/***************************************************************************//**
* @file
* @brief Simple Button Driver
*******************************************************************************
* # License
* <b>Copyright 2019 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* SPDX-License-Identifier: Zlib
*
* The licensor of this software is Silicon Laboratories Inc.
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*
******************************************************************************/
#include "sl_simple_button.h"
#include "sl_simple_button_config.h"
#include "sl_clock_manager.h"
#if (SL_SIMPLE_BUTTON_DEBOUNCE_BITS < 1U)
#undef SL_SIMPLE_BUTTON_DEBOUNCE_BITS
#define SL_SIMPLE_BUTTON_DEBOUNCE_BITS 1U
#endif
#if (SL_SIMPLE_BUTTON_DEBOUNCE_BITS > 15U)
#undef SL_SIMPLE_BUTTON_DEBOUNCE_BITS
#define SL_SIMPLE_BUTTON_DEBOUNCE_BITS 15U
#endif
static const uint16_t check_press = (uint16_t)(0xffff << SL_SIMPLE_BUTTON_DEBOUNCE_BITS);
static const uint16_t check_release = (uint16_t)(~(0x1 << SL_SIMPLE_BUTTON_DEBOUNCE_BITS));
static const uint16_t debounce_window = (uint16_t)(0xffff << (SL_SIMPLE_BUTTON_DEBOUNCE_BITS + 1));
/***************************************************************************//**
* An internal callback called in interrupt context whenever a button changes
* its state. (mode - SL_SIMPLE_BUTTON_MODE_INTERRUPT)
*
* @note The button state is updated by this function. The application callback
* should not update it again.
*
* @param[in] interrupt_no Interrupt number (pin number)
* @param[in] ctx Pointer to button handle
******************************************************************************/
static void sli_simple_button_on_change(uint8_t interrupt_no, void *ctx)
{
(void)interrupt_no;
sl_button_t *button = (sl_button_t *)ctx;
sl_simple_button_context_t *simple_button = button->context;
sl_gpio_t gpio = {
.port = simple_button->port,
.pin = simple_button->pin
};
bool pin_value;
if (simple_button->state != SL_SIMPLE_BUTTON_DISABLED) {
sl_gpio_get_pin_input(&gpio, &pin_value);
simple_button->state = ((bool)pin_value == SL_SIMPLE_BUTTON_POLARITY);
sl_button_on_change(button);
}
}
sl_status_t sl_simple_button_init(const sl_button_t *handle)
{
int32_t interrupt_em4, interrupt_ext;
sl_status_t status;
sl_button_t *button = (sl_button_t *)handle;
sl_simple_button_context_t *simple_button = button->context;
sl_gpio_t gpio = {
.port = simple_button->port,
.pin = simple_button->pin
};
bool pin_value;
sl_clock_manager_enable_bus_clock(SL_BUS_CLOCK_GPIO);
sl_gpio_set_pin_mode(&gpio, SL_SIMPLE_BUTTON_GPIO_MODE, SL_SIMPLE_BUTTON_GPIO_DOUT);
sl_gpio_get_pin_input(&gpio, &pin_value);
simple_button->state = ((bool)pin_value == SL_SIMPLE_BUTTON_POLARITY);
if (simple_button->mode == SL_SIMPLE_BUTTON_MODE_INTERRUPT) {
interrupt_em4 = SL_GPIO_INTERRUPT_UNAVAILABLE;
interrupt_ext = SL_GPIO_INTERRUPT_UNAVAILABLE;
// Try to register an EM4WU interrupt for the given pin
status = sl_gpio_configure_wakeup_em4_interrupt(&gpio,
&interrupt_em4,
SL_SIMPLE_BUTTON_POLARITY,
(sl_gpio_irq_callback_t)sli_simple_button_on_change,
button);
if (interrupt_em4 == SL_GPIO_INTERRUPT_UNAVAILABLE) {
// if the pin not EM4WU-compatible, instead register a regualr interrupt
status = sl_gpio_configure_external_interrupt(&gpio,
&interrupt_ext,
SL_GPIO_INTERRUPT_RISING_FALLING_EDGE,
(sl_gpio_irq_callback_t)sli_simple_button_on_change,
button);
EFM_ASSERT(status == SL_STATUS_OK);
} else {
// If the pin is EM4WU-compatible, setup the pin as an EM4WU pin
// Since EM4WU interrupts are level-sensitive and not edge-sensitive, also register a regular edge-sensitive interrupt to capture the other edge
uint8_t flags;
if (SL_SIMPLE_BUTTON_POLARITY == 0) {
flags = SL_GPIO_INTERRUPT_RISING_EDGE;
} else if (SL_SIMPLE_BUTTON_POLARITY == 1) {
flags = SL_GPIO_INTERRUPT_FALLING_EDGE;
}
status = sl_gpio_configure_external_interrupt(&gpio,
&interrupt_ext,
flags,
(sl_gpio_irq_callback_t)sli_simple_button_on_change,
button);
EFM_ASSERT(status == SL_STATUS_OK);
}
}
return SL_STATUS_OK;
}
sl_button_state_t sl_simple_button_get_state(const sl_button_t *handle)
{
sl_button_t *button = (sl_button_t *)handle;
sl_simple_button_context_t *simple_button = button->context;
return simple_button->state;
}
void sl_simple_button_poll_step(const sl_button_t *handle)
{
sl_button_t *button = (sl_button_t *)handle;
sl_simple_button_context_t *simple_button = button->context;
bool button_press, pin_value;
sl_gpio_t gpio = {
.port = simple_button->port,
.pin = simple_button->pin
};
if (simple_button->state == SL_SIMPLE_BUTTON_DISABLED) {
return;
}
sl_gpio_get_pin_input(&gpio, &pin_value);
button_press = (bool)pin_value;
if (simple_button->mode == SL_SIMPLE_BUTTON_MODE_POLL_AND_DEBOUNCE) {
uint16_t history = simple_button->history;
history = (history << 1) | (button_press ^ SL_SIMPLE_BUTTON_POLARITY) | (debounce_window);
if (history == check_press) {
simple_button->state = SL_SIMPLE_BUTTON_PRESSED;
}
if (history == check_release) {
simple_button->state = SL_SIMPLE_BUTTON_RELEASED;
}
simple_button->history = history;
} else if (simple_button->mode == SL_SIMPLE_BUTTON_MODE_POLL) {
simple_button->state = (button_press == SL_SIMPLE_BUTTON_POLARITY);
}
}
void sl_simple_button_enable(const sl_button_t *handle)
{
sl_button_t *button = (sl_button_t *)handle;
sl_simple_button_context_t *simple_button = button->context;
// Return if the button is not disabled
if (simple_button->state != SL_SIMPLE_BUTTON_DISABLED) {
return;
}
// Clear history
simple_button->history = 0;
// Reinit button
sl_simple_button_init(handle);
}
void sl_simple_button_disable(const sl_button_t *handle)
{
sl_button_t *button = (sl_button_t *)handle;
sl_simple_button_context_t *simple_button = button->context;
// Return if the button is disabled
if (simple_button->state == SL_SIMPLE_BUTTON_DISABLED) {
return;
}
if (simple_button->mode == SL_SIMPLE_BUTTON_MODE_INTERRUPT) {
sl_gpio_deconfigure_external_interrupt(simple_button->pin);
}
// Disable the button
simple_button->state = SL_SIMPLE_BUTTON_DISABLED;
}

View File

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

View File

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

View File

@@ -0,0 +1,183 @@
/***************************************************************************//**
* @file
* @brief LED Driver
*******************************************************************************
* # License
* <b>Copyright 2019 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* SPDX-License-Identifier: Zlib
*
* The licensor of this software is Silicon Laboratories Inc.
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*
******************************************************************************/
#ifndef SL_LED_H
#define SL_LED_H
#include <stdint.h>
#include "sl_status.h"
#ifdef __cplusplus
extern "C" {
#endif
/***************************************************************************//**
* @addtogroup led LED Driver
* @brief Generic LED Driver
* @{
******************************************************************************/
/*******************************************************************************
****************************** DEFINES ************************************
******************************************************************************/
#define SL_LED_CURRENT_STATE_OFF 0U ///< LED state off
#define SL_LED_CURRENT_STATE_ON 1U ///< LED state on
/*******************************************************************************
***************************** DATA TYPES **********************************
******************************************************************************/
typedef uint8_t sl_led_state_t; ///< LED state
/// A LED instance
typedef struct {
void *context; ///< The context for this LED instance
sl_status_t (*init)(void *context); ///< Member function to initialize LED instance
void (*turn_on)(void *context); ///< Member function to turn on LED
void (*turn_off)(void *context); ///< Member function to turn off LED
void (*toggle)(void *context); ///< Member function to toggle LED
sl_led_state_t (*get_state)(void *context); ///< Member function to retrieve LED state
} sl_led_t;
/*******************************************************************************
***************************** PROTOTYPES **********************************
******************************************************************************/
/***************************************************************************//**
* Initialize the LED driver. Call this function before any other LED
* function. Initializes the selected LED GPIO, mode, and polarity.
*
* @param[in] led_handle Pointer to instance of sl_led_t to initialize
*
* @return Status Code:
* - SL_STATUS_OK
******************************************************************************/
sl_status_t sl_led_init(const sl_led_t *led_handle);
/***************************************************************************//**
* Turn on the LED.
*
* @param[in] led_handle Pointer to instance of sl_led_t to turn on
******************************************************************************/
void sl_led_turn_on(const sl_led_t *led_handle);
/***************************************************************************//**
* Turn off the LED.
*
* @param[in] led_handle Pointer to instance of sl_led_t to turn off
******************************************************************************/
void sl_led_turn_off(const sl_led_t *led_handle);
/***************************************************************************//**
* Toggle the LED. Turn it on if it is off, and off if it is on.
*
* @param[in] led_handle Pointer to instance of sl_led_t to toggle
******************************************************************************/
void sl_led_toggle(const sl_led_t *led_handle);
/***************************************************************************//**
* Get the current state of the LED.
*
* @param[in] led_handle Pointer to instance of sl_led_t to check
*
* @return sl_led_state_t Current state of LED. 1 for on, 0 for off
******************************************************************************/
sl_led_state_t sl_led_get_state(const sl_led_t *led_handle);
/** @} (end group led) */
// ******** THE REST OF THE FILE IS DOCUMENTATION ONLY !***********************
/// @addtogroup led LED Driver
/// @{
///
/// @details
///
///
/// @n @section leddrv_intro Introduction
///
/// The LED driver is a platfom level software module that manages the control of
/// various types of LEDs. There are currently two types of LEDs supported by the
/// LED driver:
///
/// @li @ref simple_led
/// @li @ref simple_rgbw_pwm_led
///
/// The common LED functions are called through the generic LED driver, while other
/// functions specific to a certain type of LED are called directly through their own
/// driver.
///
/// @n @section leddrv_config Configuration
///
/// All LED instances are configured using an @ref sl_led_t struct along with a
/// type-specific context struct, and sometimes additional structs. For `sl_led_XXX`
/// functions, the `sl_led_t *led_handle` is used, while for `sl_simple_led_XXX`
/// functions, the `sl_simple_led_context_t *context` is used.
///
/// These structs are automatically generated when an LED is set up using Simplicity
/// Studio's wizard. Specific configuration setups for the various LED types are
/// described in the following sections.
///
/// - [Simple LED Configuration](/gecko-platform/<docspace-docleaf-version>/platform-driver/simple-led#simple-led-configuration)
/// - [RGBW PWM LED Configuration](/gecko-platform/<docspace-docleaf-version>/platform-driver/simple-rgb-pwm-led#rgb-pwm-led-configuration)
///
/// @n @section leddrv_usage Usage
///
/// Once the LED structs are defined, the common LED functions can be called being passed an instance
/// of sl_led_t, which will be redirected to calling the type specific version of that function. The
/// common functions include the following:
///
/// @li @ref sl_led_init
/// @li @ref sl_led_turn_on
/// @li @ref sl_led_turn_off
/// @li @ref sl_led_toggle
/// @li @ref sl_led_get_state
///
/// These functions allow for initializing the LED, turning it on and off, toggling it, and retrieving
/// its current state (on/off). Other functions specific to certain types of LEDs are called through
/// their respective APIs. The usages of the different types of LEDs are described in detail in the
/// following sections:
///
/// @li @ref simple_led_usage
/// @li @ref rgbw_led_usage
///
/// Ensure that the appropriate context type is used in the function calls:
/// - Use `sl_led_t *led_handle` for `sl_led_XXX` functions.
/// - Use `sl_simple_led_context_t *context` for `sl_simple_led_XXX` functions.
///
/// These distinctions are handled by the Simplicity Studio auto-generated code.
///
/// @} end group led ********************************************************/
#ifdef __cplusplus
}
#endif
#endif // SL_LED_H

View File

@@ -0,0 +1,226 @@
/***************************************************************************//**
* @file
* @brief Simple LED Driver
*******************************************************************************
* # License
* <b>Copyright 2019 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* SPDX-License-Identifier: Zlib
*
* The licensor of this software is Silicon Laboratories Inc.
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*
******************************************************************************/
#ifndef SL_SIMPLE_LED_H
#define SL_SIMPLE_LED_H
#include "sl_led.h"
#include "sl_gpio.h"
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/***************************************************************************//**
* @addtogroup led
* @{
******************************************************************************/
/***************************************************************************//**
* @addtogroup simple_led Simple LED Driver
* @brief Simple LED Driver can be used to execute basic LED functionalities
* such as on, off, toggle, or retrive the on/off status on Silicon Labs
* devices. Subsequent sections provide more insight into this module.
* @{
******************************************************************************/
/*******************************************************************************
****************************** DEFINES ************************************
******************************************************************************/
#define SL_SIMPLE_LED_POLARITY_ACTIVE_LOW 0U ///< LED Active polarity Low
#define SL_SIMPLE_LED_POLARITY_ACTIVE_HIGH 1U ///< LED Active polarity High
/*******************************************************************************
***************************** DATA TYPES **********************************
******************************************************************************/
typedef uint8_t sl_led_polarity_t; ///< LED GPIO polarities (active high/low)
/// A Simple LED instance
typedef struct {
sl_gpio_port_t port; ///< LED port
uint8_t pin; ///< LED pin
sl_led_polarity_t polarity; ///< Initial state of LED
} sl_simple_led_context_t;
/*******************************************************************************
***************************** PROTOTYPES **********************************
******************************************************************************/
/***************************************************************************//**
* Initialize the simple LED driver.
*
* @param[in] led_handle Pointer to simple-led specific data:
* - sl_simple_led_context_t
*
* @return Status Code:
* - SL_STATUS_OK
******************************************************************************/
sl_status_t sl_simple_led_init(void *led_handle);
/***************************************************************************//**
* Turn on a simple LED.
*
* @param[in] led_handle Pointer to simple-led specific data:
* - sl_simple_led_context_t
*
******************************************************************************/
void sl_simple_led_turn_on(void *led_handle);
/***************************************************************************//**
* Turn off a simple LED.
*
* @param[in] led_handle Pointer to simple-led specific data:
* - sl_simple_led_context_t
*
******************************************************************************/
void sl_simple_led_turn_off(void *led_handle);
/***************************************************************************//**
* Toggle a simple LED.
*
* @param[in] led_handle Pointer to simple-led specific data:
* - sl_simple_led_context_t
*
******************************************************************************/
void sl_simple_led_toggle(void *led_handle);
/***************************************************************************//**
* Get the current state of the simple LED.
*
* @param[in] led_handle Pointer to simple-led specific data:
* - sl_simple_led_context_t
*
* @return sl_led_state_t Current state of simple LED. 1 for on, 0 for off
******************************************************************************/
sl_led_state_t sl_simple_led_get_state(void *led_handle);
/** @} (end group simple_led) */
/** @} (end group led) */
// ******** THE REST OF THE FILE IS DOCUMENTATION ONLY !***********************
/// @addtogroup simple_led Simple LED Driver
/// @{
///
/// @details
///
///
/// @n @section simple_led_intro Introduction
///
/// The Simple LED driver is a module of the LED driver that provides the functionality
/// to control simple on/off LEDs.
///
/// @n @section simple_led_config Simple LED Configuration
///
/// Simple LEDs use the @ref sl_led_t struct and their @ref sl_simple_led_context_t
/// struct. These are automatically generated into the following files, as well as
/// instance specific headers with macro definitions in them. The samples below
/// are for a single instance called "inst0".
///
/// @code{.c}
///// sl_simple_led_instances.c
///
///#include "sl_simple_led.h"
///#include "sl_gpio.h"
///#include "sl_simple_led_inst0_config.h"
///
///sl_simple_led_context_t simple_inst0_context = {
/// .port = SL_SIMPLE_LED_INST0_PORT,
/// .pin = SL_SIMPLE_LED_INST0_PIN,
/// .polarity = SL_SIMPLE_LED_INST0_POLARITY,
///};
///
///const sl_led_t sl_led_inst0 = {
/// .context = &simple_inst0_context,
/// .init = sl_simple_led_init,
/// .turn_on = sl_simple_led_turn_on,
/// .turn_off = sl_simple_led_turn_off,
/// .toggle = sl_simple_led_toggle,
/// .get_state = sl_simple_led_get_state,
///};
///
///void sl_simple_led_init_instances(void)
///{
/// sl_led_init(&sl_led_inst0);
///}
/// @endcode
///
/// @note The sl_simple_led_instances.c file is shown with only one instance, but if more
/// were in use they would all appear in this .c file.
///
/// @code{.c}
///// sl_simple_led_instances.h
///
///#ifndef SL_SIMPLE_LED_INSTANCES_H
///#define SL_SIMPLE_LED_INSTANCES_H
///
///#include "sl_simple_led.h"
///
///extern const sl_led_t sl_led_inst0;
///
///void sl_simple_led_init_instances(void);
///
///#endif // SL_SIMPLE_LED_INIT_H
/// @endcode
///
/// @note The sl_simple_led_instances.h file is shown with only one instance, but if more
/// were in use they would all appear in this .h file.
///
/// @n @section simple_led_usage Simple LED Usage
///
/// The simple LED driver is for LEDs with basic on off functionality, and there
/// are no additional functions beyond those in the common driver. The LEDs can be
/// turned on and off, toggled, and their on/off state can be retrieved. The following
/// code shows how to control these LEDs. An LED should always be initialized before
/// calling any other functions with it.
///
/// @code{.c}
///// initialize simple LED
///sl_simple_led_init(&simple_led_inst0);
///
///// turn on simple LED, turn off simple LED, and toggle the simple LED
///sl_simple_led_turn_on(&simple_led_inst0);
///sl_simple_led_turn_off(&simple_led_inst0);
///sl_simple_led_toggle(&simple_led_inst0);
///
///// get the state of the simple LED
///sl_led_state_t state = sl_simple_led_get_state(&simple_led_instance0);
/// @endcode
///
/// @} end group simple_led ********************************************************/
#ifdef __cplusplus
}
#endif
#endif // SL_SIMPLE_LED_H

View File

@@ -0,0 +1,56 @@
/***************************************************************************//**
* @file
* @brief LED Driver
*******************************************************************************
* # License
* <b>Copyright 2019 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* SPDX-License-Identifier: Zlib
*
* The licensor of this software is Silicon Laboratories Inc.
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*
******************************************************************************/
#include "sl_led.h"
sl_status_t sl_led_init(const sl_led_t *led_handle)
{
return led_handle->init(led_handle->context);
}
void sl_led_turn_on(const sl_led_t *led_handle)
{
led_handle->turn_on(led_handle->context);
}
void sl_led_turn_off(const sl_led_t *led_handle)
{
led_handle->turn_off(led_handle->context);
}
void sl_led_toggle(const sl_led_t *led_handle)
{
led_handle->toggle(led_handle->context);
}
sl_led_state_t sl_led_get_state(const sl_led_t *led_handle)
{
return led_handle->get_state(led_handle->context);
}

View File

@@ -0,0 +1,104 @@
/***************************************************************************//**
* @file
* @brief Simple LED Driver
*******************************************************************************
* # License
* <b>Copyright 2019 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* SPDX-License-Identifier: Zlib
*
* The licensor of this software is Silicon Laboratories Inc.
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*
******************************************************************************/
#include "sl_simple_led.h"
#include "sl_gpio.h"
#include "sl_clock_manager.h"
sl_status_t sl_simple_led_init(void *context)
{
sl_simple_led_context_t *led = context;
sl_clock_manager_enable_bus_clock(SL_BUS_CLOCK_GPIO);
sl_gpio_t gpio;
gpio.port = led->port;
gpio.pin = led->pin;
sl_gpio_set_pin_mode(&gpio,
SL_GPIO_MODE_PUSH_PULL,
!led->polarity);
return SL_STATUS_OK;
}
void sl_simple_led_turn_on(void *context)
{
sl_simple_led_context_t *led = context;
sl_gpio_t gpio;
gpio.port = led->port;
gpio.pin = led->pin;
if (led->polarity == SL_SIMPLE_LED_POLARITY_ACTIVE_LOW) {
sl_gpio_clear_pin(&gpio);
} else {
sl_gpio_set_pin(&gpio);
}
}
void sl_simple_led_turn_off(void *context)
{
sl_simple_led_context_t *led = context;
sl_gpio_t gpio;
gpio.port = led->port;
gpio.pin = led->pin;
if (led->polarity == SL_SIMPLE_LED_POLARITY_ACTIVE_LOW) {
sl_gpio_set_pin(&gpio);
} else {
sl_gpio_clear_pin(&gpio);
}
}
void sl_simple_led_toggle(void *context)
{
sl_simple_led_context_t *led = context;
sl_gpio_t gpio;
gpio.port = led->port;
gpio.pin = led->pin;
sl_gpio_toggle_pin(&gpio);
}
sl_led_state_t sl_simple_led_get_state(void *context)
{
sl_simple_led_context_t *led = context;
sl_led_state_t value;
sl_gpio_t gpio;
bool pin_value;
gpio.port = led->port;
gpio.pin = led->pin;
sl_gpio_get_pin_output(&gpio, &pin_value);
value = (sl_led_state_t)pin_value;
if (led->polarity == SL_SIMPLE_LED_POLARITY_ACTIVE_LOW) {
return !value;
} else {
return value;
}
}