蓝牙BLE---DA14683的GPIO中断按键源码
程序员文章站
2022-05-25 17:06:56
...
ad_gpio_intr.h
/**
* \addtogroup BSP
* \{
* \addtogroup ADAPTERS
* \{
* \addtogroup GPIO_INTR
* \{
*/
/**
*****************************************************************************************
*
* @file ad_gpio_intr.h
*
* @brief WKUP adapter API
*
* Copyright (C) 2015. Dialog Semiconductor Ltd, unpublished work. This computer
* program includes Confidential, Proprietary Information and is a Trade Secret of
* Dialog Semiconductor Ltd. All use, disclosure, and/or reproduction is prohibited
* unless authorized in writing. All Rights Reserved.
*
* <[email protected]> and contributors.
*
*****************************************************************************************
*/
#ifndef AD_GPIO_INTR_H_
#define AD_GPIO_INTR_H_
#include <hw_gpio.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* \brief Device gpio pointer, handle to use with ad_gpio_intr_register(), ad_gpio_intr_unregister() etc.
*
*/
#ifndef AD_GPIO_INTR_INSTANCE
/**
* \brief Entry for gpio interrupt
*
* \param [in] _name name that will be later used to refer to instance
* \param [in] _port port id of triggering pin
* \param [in] _pin pin id of triggering pin
* \param [in] _press_callback function to be called when interrupt occurs
* \param [in] _release_callback function to be called when interrupt occurs
*
*/
#define AD_GPIO_INTR_INSTANCE(_name, _port, _pin, _press_callback, _release_callback) \
INITIALISED_PRIVILEGED_DATA ad_gpio_intr_config dev_##_name = { \
.port = _port, \
.pin = _pin, \
.pressed = false, \
.press_cb = _press_callback, \
.release_cb = _release_callback, \
.next_element = NULL, \
}; \
INITIALISED_PRIVILEGED_DATA ad_gpio_intr_config *_name = &dev_##_name;
#endif
/**
* \brief Definition of callback function
*/
typedef void (*ad_gpio_intr_cb)(void);
/**
* \brief Definition of the structure of gpio interrupt instance
*/
typedef struct ad_gpio_intr_config {
HW_GPIO_PORT port;
HW_GPIO_PIN pin;
bool pressed;
ad_gpio_intr_cb press_cb;
ad_gpio_intr_cb release_cb;
struct ad_gpio_intr_config *next_element;
} ad_gpio_intr_config;
/**
* \brief Initialize adapter environment
*/
void ad_gpio_intr_init(void);
/**
* \brief Register instance and if necessary setup wkup driver
*
* \param [in] cfg handle of the instance (the _name field of AD_GPIO_INTR_INSTANCE macro)
*/
void ad_gpio_intr_register(ad_gpio_intr_config *cfg);
/**
* \brief Unregister instance
*
* \param [in] cfg handle of the instance (the _name field of AD_GPIO_INTR_INSTANCE macro)
*/
void ad_gpio_intr_unregister(ad_gpio_intr_config *cfg);
/**
* \brief Check if instance has been registered
*
* \param [in] cfg handle of the instance (the _name field of AD_GPIO_INTR_INSTANCE macro)
*
* \return true if instance has been registered, false otherwise
*/
bool ad_gpio_intr_check_registered(ad_gpio_intr_config *cfg);
/**
* \brief Check if interrupt has been handled by checking the level of the specific irq line
*
* \param [in] cfg handle of the instance (the _name field of AD_GPIO_INTR_INSTANCE macro)
*
* \return true if instance has been handled, false otherwise
*/
bool ad_gpio_irq_handled(ad_gpio_intr_config *cfg);
#ifdef __cplusplus
extern }
#endif
#endif /* AD_GPIO_INTR_H_ */
/**
* \}
* \}
* \}
*/
ad_gpio_intr.c
/**
* \addtogroup BSP
* \{
* \addtogroup ADAPTERS
* \{
* \addtogroup GPIO_INTR
* \{
*/
/**
*****************************************************************************************
*
* @file ad_gpio_intr.c
*
* @brief WKUP adapter implementation
*
* Copyright (C) 2015. Dialog Semiconductor Ltd, unpublished work. This computer
* program includes Confidential, Proprietary Information and is a Trade Secret of
* Dialog Semiconductor Ltd. All use, disclosure, and/or reproduction is prohibited
* unless authorized in writing. All Rights Reserved.
*
* <[email protected]> and contributors.
*
*****************************************************************************************
*/
#if dg_configUSE_HW_KEYBOARD_SCANNER
#include <stdint.h>
#include "sdk_defs.h"
#include "interrupts.h"
#include <sys_power_mgr.h>
#include <ad_gpio_intr.h>
#include <assert.h>
#include <stdarg.h>
#include <platform_devices.h>
#include <hw_wkup.h>
#include "hw_keyboard_scanner.h"
#include "hw_cpm.h"
/*
* \brief Definitions
*/
#define BUFFER_SIZE 16 //size must be a base-2 number
#define WKUP_INT_PRIO 1
/*
* \brief Forward function declarations
*/
static int ad_kbscn_msg_cb(void);
static int ad_kbscn_fifo_over_cb(void);
static void ad_wkup_cb(void);
static void ad_gpio_intr_wake_up_ind(bool value);
static bool ad_gpio_intr_prepare_for_sleep(void);
static void ad_gpio_intr_sleep_cancel(void);
static void ad_gpio_intr_xtal16m_ready_ind(void);
/*
* \brief Global variables
*/
struct ad_gpio_intr_env_t {
OS_MUTEX ad_gpio_intr_mutex;
ad_gpio_intr_config *head_config;
};
const adapter_call_backs_t ad_gpio_intr_pm_call_backs = {
.ad_prepare_for_sleep = ad_gpio_intr_prepare_for_sleep,
.ad_sleep_canceled = ad_gpio_intr_sleep_cancel,
.ad_wake_up_ind = ad_gpio_intr_wake_up_ind,
.ad_xtal16m_ready_ind = ad_gpio_intr_xtal16m_ready_ind,
.ad_sleep_preparation_time = 0,
};
INITIALISED_PRIVILEGED_DATA static wkup_config ad_gpio_intr_wkup_cfg = {
.debounce = 0,
#if (dg_configBLACK_ORCA_IC_REV == BLACK_ORCA_IC_REV_A)
.threshold = 1,
#endif
};
INITIALISED_PRIVILEGED_DATA static uint8_t columns[] = {
UNUSED_INDEX,
UNUSED_INDEX,
UNUSED_INDEX,
UNUSED_INDEX,
UNUSED_INDEX,
UNUSED_INDEX,
UNUSED_INDEX,
UNUSED_INDEX,
UNUSED_INDEX,
UNUSED_INDEX,
};
INITIALISED_PRIVILEGED_DATA static uint8_t rows[] = {
UNUSED_INDEX,
};
PRIVILEGED_DATA static struct kbscn_msg_tag msg_buf[BUFFER_SIZE];
INITIALISED_PRIVILEGED_DATA struct kbscn_init_tag ad_gpio_intr_kbscn_init_env = {
.columns = columns,
.rows = rows,
.num_columns = sizeof(columns),
.num_rows = sizeof(rows),
.row_scan_active_time = 1, // 1 + 1w + 1z = 3 cycles x (div/16 usec) = 3 usec => scan cycle = 1 * 3 = 3 usec
.debounce_press_time = 5, // 5 * scan cycle = 15 usec
.debounce_release_time = 5, // 5 * scan cycle = 15 usec
.inactive_time = 0,
.clock_div = KBSCN_PCLK_DIV16, // 16MHz / div = 1MHz
.inactivity_cb = NULL,
.fifo_under_cb = NULL,
.fifo_over_cb = ad_kbscn_fifo_over_cb,
.msg_cb = ad_kbscn_msg_cb,
.msg_buf = msg_buf,
.msg_buf_sz = BUFFER_SIZE,
.msg_evt = true,
.inactive_evt = false,
.fifo_evt = true,
};
PRIVILEGED_DATA static uint32_t msg_wr_idx = 0, msg_rd_idx = 0;
PRIVILEGED_DATA static struct ad_gpio_intr_env_t ad_gpio_intr_env;
/*
* \brief Functions
*/
void ad_gpio_intr_init(void)
{
if (ad_gpio_intr_env.ad_gpio_intr_mutex == NULL)
{
OS_MUTEX_CREATE(ad_gpio_intr_env.ad_gpio_intr_mutex);
OS_ASSERT(ad_gpio_intr_env.ad_gpio_intr_mutex);
pm_register_adapter(&ad_gpio_intr_pm_call_backs);
hw_wkup_init(NULL);
hw_wkup_set_debounce_time(ad_gpio_intr_wkup_cfg.debounce);
#if 0//(dg_configBLACK_ORCA_IC_REV == BLACK_ORCA_IC_REV_A)
hw_wkup_set_counter_threshold(ad_gpio_intr_wkup_cfg.threshold);
hw_wkup_reset_counter();
#endif
}
}
void ad_gpio_intr_register(ad_gpio_intr_config *cfg)
{
int i;
ad_gpio_intr_config *cfg_ptr;
if (!cfg) {
return;
}
OS_MUTEX_GET(ad_gpio_intr_env.ad_gpio_intr_mutex, OS_MUTEX_FOREVER);
cfg_ptr = ad_gpio_intr_env.head_config;
if (!ad_gpio_intr_env.head_config){
ad_gpio_intr_env.head_config = cfg;
hw_wkup_register_interrupt(ad_wkup_cb, WKUP_INT_PRIO);
} else {
while (cfg_ptr) {
///Check if already added
if (cfg_ptr == cfg)
break;
///Add it if not in the list
if (cfg_ptr->next_element == NULL){
cfg_ptr->next_element = cfg;
break;
}
cfg_ptr = cfg_ptr->next_element;
}
}
for (i = 0; i < sizeof(columns); i++) {
HW_GPIO_PORT port = (0xF & (CONV_INDEX_TO_PORT_PIN(columns[i]) >> 4));
HW_GPIO_PIN pin = (0xF & (CONV_INDEX_TO_PORT_PIN(columns[i])));
if((cfg->port == port) && (cfg->pin == pin))
break;
}
if (i == sizeof(columns)) {
for (i = 0; i < sizeof(columns); i++) {
if (columns[i] == UNUSED_INDEX) {
columns[i] = CONV_PORT_PIN_TO_INDEX(
((0x0F & cfg->port) << 4) | (0x0F & cfg->pin));
break;
}
}
}
OS_ASSERT(i < sizeof(columns)); //No available slot in columns array
OS_MUTEX_PUT(ad_gpio_intr_env.ad_gpio_intr_mutex);
hw_wkup_freeze();
if (hw_kbscn_get_status())
hw_kbscn_disable();
hw_kbscn_init(&ad_gpio_intr_kbscn_init_env, &msg_wr_idx, &msg_rd_idx);
hw_wkup_configure_pin(cfg->port, cfg->pin, true, HW_WKUP_PIN_STATE_LOW);
hw_kbscn_enable();
hw_wkup_unfreeze();
hw_kbscn_activate_msg_evt();
}
void ad_gpio_intr_unregister(ad_gpio_intr_config *cfg)
{
int i;
bool remove = true;
ad_gpio_intr_config *cfg_ptr;
if (!cfg) {
return;
}
for (i = 0; i < sizeof(columns); i++) {
HW_GPIO_PORT port = (0xF & (CONV_INDEX_TO_PORT_PIN(columns[i]) >> 4));
HW_GPIO_PIN pin = (0xF & (CONV_INDEX_TO_PORT_PIN(columns[i])));
if ((cfg->port == port) && (cfg->pin == pin))
break;
}
if (i == sizeof(columns))
return;
OS_MUTEX_GET(ad_gpio_intr_env.ad_gpio_intr_mutex, OS_MUTEX_FOREVER);
cfg_ptr = ad_gpio_intr_env.head_config;
if(ad_gpio_intr_env.head_config == cfg){
ad_gpio_intr_env.head_config = NULL;
hw_wkup_unregister_interrupt();
} else {
while (cfg_ptr) {
if (cfg_ptr->next_element == cfg) {
cfg_ptr->next_element = cfg->next_element;
} else if((cfg_ptr->port == cfg->port) && (cfg_ptr->pin == cfg->pin)) {
remove = false;
break;
}
cfg_ptr = cfg_ptr->next_element;
}
}
if (remove)
columns[i] = UNUSED_INDEX;
OS_MUTEX_PUT(ad_gpio_intr_env.ad_gpio_intr_mutex);
hw_wkup_configure_pin(cfg->port, cfg->pin, false, 0);
}
bool ad_gpio_intr_check_registered(ad_gpio_intr_config *cfg)
{
bool ret = false;
ad_gpio_intr_config *cfg_ptr;
if (!cfg) {
return ret;
}
OS_MUTEX_GET(ad_gpio_intr_env.ad_gpio_intr_mutex, OS_MUTEX_FOREVER);
cfg_ptr = ad_gpio_intr_env.head_config;
while (cfg_ptr) {
if (cfg_ptr == cfg) {
ret = true;
break;
}
cfg_ptr = cfg_ptr->next_element;
}
OS_MUTEX_PUT(ad_gpio_intr_env.ad_gpio_intr_mutex);
return ret;
}
bool ad_gpio_irq_handled(ad_gpio_intr_config *cfg)
{
volatile ad_gpio_intr_config *cfg_gbl = cfg;
bool status, ret = true;
cfg_gbl->pressed = false;
hw_cpm_delay_usec(200);
status = hw_gpio_get_pin_status(cfg->port, cfg->pin);
if(!cfg_gbl->pressed){
cfg_gbl->pressed = !status;
ret = status;
}
return ret;
}
static void ad_wkup_cb(void)
{
hw_wkup_reset_interrupt();
hw_wkup_freeze();
}
static void ad_kbscn_msg_consume(void)
{
struct kbscn_msg_tag *p_msg;
ad_gpio_intr_config *cfg_ptr;
while (msg_rd_idx != msg_wr_idx) {
p_msg = &msg_buf[msg_rd_idx];
if (!(p_msg->flags & LAST_MSG)) {
HW_GPIO_PORT port = (0xF & (CONV_INDEX_TO_PORT_PIN(columns[p_msg->column]) >> 4));
HW_GPIO_PIN pin = (0xF & (CONV_INDEX_TO_PORT_PIN(columns[p_msg->column])));
OS_ASSERT(p_msg->row == 0);
if (p_msg->flags & PRESSED) {
cfg_ptr = ad_gpio_intr_env.head_config;
while (cfg_ptr) {
if ((cfg_ptr->port == port) && (cfg_ptr->pin == pin) && !cfg_ptr->pressed) {
cfg_ptr->pressed = true;
if (cfg_ptr->press_cb) {
cfg_ptr->press_cb();
}
}
cfg_ptr = cfg_ptr->next_element;
}
}
if (!p_msg->flags) {
cfg_ptr = ad_gpio_intr_env.head_config;
while (cfg_ptr) {
if ((cfg_ptr->port == port) && (cfg_ptr->pin == pin) && cfg_ptr->pressed) {
cfg_ptr->pressed = false;
if (cfg_ptr->release_cb) {
cfg_ptr->release_cb();
}
}
cfg_ptr = cfg_ptr->next_element;
}
}
}
msg_rd_idx++;
msg_rd_idx &= (BUFFER_SIZE - 1); // fast modulo operation
}
}
static int ad_kbscn_msg_cb(void)
{
ad_kbscn_msg_consume();
/* Re-enable fifo irq in case of buffer overflow */
hw_kbscn_activate_msg_evt();
return 0;
}
static int ad_kbscn_fifo_over_cb(void)
{
hw_kbscn_disable();
hw_kbscn_reset_fifo();
/* Consume any events in buffer */
ad_kbscn_msg_consume();
/* Reset buffer */
msg_wr_idx = 0;
msg_rd_idx = 0;
hw_kbscn_enable();
hw_kbscn_activate_msg_evt();
return 0;
}
static void ad_gpio_intr_wake_up_ind(bool value)
{
hw_kbscn_init(&ad_gpio_intr_kbscn_init_env, &msg_wr_idx, &msg_rd_idx);
hw_kbscn_enable();
hw_kbscn_activate_msg_evt();
}
static void ad_gpio_intr_sleep_cancel(void)
{
hw_wkup_freeze();
}
static void ad_gpio_intr_xtal16m_ready_ind(void) {
/* nothing to do */
}
static bool ad_gpio_intr_prepare_for_sleep(void)
{
ad_gpio_intr_config *cfg_ptr;
for (int i = 0; i < sizeof(columns); i++) {
HW_GPIO_PORT port;
HW_GPIO_PIN pin;
if (columns[i] == UNUSED_INDEX)
continue;
port = 0xF & (CONV_INDEX_TO_PORT_PIN(columns[i]) >> 4);
pin = 0xF & (CONV_INDEX_TO_PORT_PIN(columns[i]));
if (!hw_gpio_get_pin_status(port, pin)){
return false;
}
}
cfg_ptr = ad_gpio_intr_env.head_config;
while (cfg_ptr) {
if (cfg_ptr->pressed) {
return false;
}
cfg_ptr = cfg_ptr->next_element;
}
hw_wkup_unfreeze();
return true;
}
#endif
/**
* \}
* \}
* \}
*/
gpio_key.h
/**
****************************************************************************************
*
* @file demo_hw.h
*
* @brief Code related to mesh reference design hardware
*
* Copyright (C) 2016-2018 Dialog Semiconductor.
* This computer program includes Confidential, Proprietary Information
* of Dialog Semiconductor. All Rights Reserved.
*
****************************************************************************************
*/
#ifndef DEMO_HW_H_
#define DEMO_HW_H_
#include <stdint.h>
#include "osal.h"
/**
* Initialize peripherals needed for demo
* These are initialized only once
*/
void hw_init(void);
/**
* Configure peripherals needed for demo
* These need to be reinitialized after sleep exit
*/
void hw_configure(void);
/**
* Trigger hardware reset
*/
void hw_trigger_reboot(void);
#endif /* DEMO_HW_H_ */
gpio_key.c
/**
****************************************************************************************
*
* @file demo_hw.c
*
* @brief Code related to mesh reference design hardware
*
* Copyright (C) 2016-2018 Dialog Semiconductor.
* This computer program includes Confidential, Proprietary Information
* of Dialog Semiconductor. All Rights Reserved.
*
****************************************************************************************
*/
#include <stdio.h>
#include <string.h>
#include "hw_led.h"
#include "hw_breath.h"
#include "hw_gpio.h"
#include "hw_wkup.h"
#include "hw_watchdog.h"
#include "hw_timer2.h"
#include "sys_power_mgr.h"
#include "hw_cpm.h"
#include "ad_gpio_intr.h"
#include "ad_spi.h"
#include "sys_rtc.h"
#include "platform_devices.h"
#include "gpio_key.h"
//#include "appl_support.h"
# define CFG_GPIO_MB_BUTTON_SW1_PORT (HW_GPIO_PORT_3)
# define CFG_GPIO_MB_BUTTON_SW1_PIN (HW_GPIO_PIN_1)
# define CFG_GPIO_MB_BUTTON_SW2_PORT (HW_GPIO_PORT_3)
# define CFG_GPIO_MB_BUTTON_SW2_PIN (HW_GPIO_PIN_2)
//uint64_t mytime = 0;
static void k1_button_pressed(void);
static void k1_button_released(void);
//Create GPIO interrupt instance for K1 button
static AD_GPIO_INTR_INSTANCE(K1_BUTTON, CFG_GPIO_MB_BUTTON_SW1_PORT, CFG_GPIO_MB_BUTTON_SW1_PIN,
k1_button_pressed, k1_button_released);
static void k2_button_pressed(void);
static void k2_button_released(void);
//Create GPIO interrupt instance for K1 button
static AD_GPIO_INTR_INSTANCE(K2_BUTTON, CFG_GPIO_MB_BUTTON_SW2_PORT, CFG_GPIO_MB_BUTTON_SW2_PIN,
k2_button_pressed, k2_button_released);
static void k2_button_pressed(void)
{
printf("k2_button_pressed\r\n");
}
static void k2_button_released(void)
{
printf("k2_button_released\r\n");
}
static void k1_button_pressed(void)
{
printf("k1_button_pressed \r\n");
//mytime = rtc_get_fromISR();
}
static void k1_button_released(void) {
// if ((rtc_get_fromISR() - mytime) > 100000)
{
printf("k1_button_released \r\n");
}
}
void hw_configure(void)
{
/* Configure Pushbutton K1 */
hw_gpio_configure_pin(CFG_GPIO_MB_BUTTON_SW1_PORT, CFG_GPIO_MB_BUTTON_SW1_PIN,
HW_GPIO_MODE_INPUT_PULLUP, HW_GPIO_FUNC_GPIO, true);
hw_gpio_configure_pin(CFG_GPIO_MB_BUTTON_SW2_PORT, CFG_GPIO_MB_BUTTON_SW2_PIN,
HW_GPIO_MODE_INPUT_PULLUP, HW_GPIO_FUNC_GPIO, true);
//mytime = rtc_get_fromISR();
}
void hw_set_mb_led1_level(uint8_t level)
{
}
void hw_init(void)
{
hw_configure();
ad_gpio_intr_init();
ad_gpio_intr_register(K1_BUTTON);
ad_gpio_intr_register(K2_BUTTON);
}
void hw_trigger_reboot(void)
{
hw_cpm_reboot_system();
}