gpio button数据结构
typedef struct {
GPIO_Port button_Port; ---- 端口
GPIO_Pin button_Pin; ---- 引脚
GPIO_BUTTON_DIFAULT_STA default_Potential; ---- 初始状态
} GPIO_Button_IO;
预制数据
static GPIO_Button_IO Button_Io_Register[BUTTON_IO_REGISTER_LEN] = {
/*BUTTON 0 IO*/
{GPIO_PORT_A, GPIO_PIN_19, HIGH_LEVEL},
/*BUTTON 1 IO*/
{GPIO_PORT_A, GPIO_PIN_20, HIGH_LEVEL},
};
按键程序入口 gpio_button_ctrl_init
void gpio_button_ctrl_init(void)
{
DRV_GPIO_BUTTON_CTRL_DBG("button_ctrl_init\n");
DRV_Board_GPIO_Button_Cfg(BUTTON_INIT, Button_Io_Register, BUTTON_IO_REGISTER_LEN); ---- 1.1
gpio_button_cb_init(); ----- 1.2
button_ctrl_run = 1;
/* start system control task */
if (OS_ThreadCreate(&g_button_ctrl_thread,
"",
gpio_button_ctrl_task, ---- 1.3
NULL,
OS_THREAD_PRIO_APP,
BUTTON_CTRL_THREAD_STACK_SIZE) != OS_OK) {
DRV_GPIO_BUTTON_CTRL_DBG("create button ctrl task failed\n");
}
COMPONENT_TRACK("end\n");
}
/**
* @brief Init or deinit gpio button pins.
* @param req: ctrl init or deinit pins.
* @param button_reg_ruff: pins list.
* @param reg_buff_len: buff len.
* @retval Component_Status: The status of driver.
*/
static GPIO_Button_Irq *Button_Irq = NULL;
static GPIO_Button_IO *Button_Reg = NULL;
static uint8_t *Button_Irq_Edge = NULL;
static uint32_t Button_Num = 0;
Component_Status DRV_Board_GPIO_Button_Cfg(GPIO_Board_Button_Req req,
GPIO_Button_IO *button_reg_ruff, uint32_t reg_buff_len)
{
if (req == BUTTON_INIT) { -------- 初始化
Button_Irq = malloc(sizeof(GPIO_Button_Irq) * reg_buff_len); // 2
Button_Irq_Edge = malloc(reg_buff_len);
Button_Reg = button_reg_ruff;
Button_Num = reg_buff_len;
}
int i = 0;
for (i = 0; i < Button_Num; i++) {
if (req == BUTTON_INIT)
GPIO_ButtonInit(i); --------------------------> 下面分析1.1.2
else
DeInit_GPIO_Button(i);
}
OS_MSleep(2);
if (req == BUTTON_DEINIT) { ---- 析构化
free(Button_Irq);
Button_Irq = NULL;
free(Button_Irq_Edge);
Button_Irq_Edge = NULL;
Button_Reg = NULL;
Button_Num = 0;
}
return COMP_OK;
}
static Component_Status GPIO_ButtonInit(uint32_t id)
{
DRV_GPIO_BUTTON_DBG("%s() id %d\n", __func__, id);
if (id >= Button_Num)
return COMP_ERROR;
GPIO_InitParam param;
param.driving = GPIO_DRIVING_LEVEL_1;
GPIO_Button_IO button = Button_Reg[id];
if (button.default_Potential == HIGH_LEVEL) { ------ 初始化为高电平
param.pull = GPIO_PULL_UP; ------ 上拉使能
Button_Irq_Edge[id] = GPIO_IRQ_EVT_FALLING_EDGE;---- irq 中断设置为下降沿触发
} else { ------ 初始化为低电平
param.pull = GPIO_PULL_DOWN; ------ 下拉使能
Button_Irq_Edge[id] = GPIO_IRQ_EVT_RISING_EDGE; ---- irq 中断设置为上升沿触发
}
param.mode = IO_EINTA; ----- 外部中断模式
HAL_GPIO_Init(button.button_Port, ----- 1.1.6 固件抽象层的gpio init接口
button.button_Pin, ¶m);
Enable_GPIO_Button(id, button.default_Potential); ---- 下面分析1.1.3
return COMP_OK;
}
static Component_Status Enable_GPIO_Button(uint32_t id, GPIO_BUTTON_DIFAULT_STA default_Potential)
{
if (id >= Button_Num)
return COMP_ERROR;
GPIO_IrqParam Irq_param;
if(default_Potential == LOW_LEVEL)
Irq_param.event = GPIO_IRQ_EVT_RISING_EDGE;
else if(default_Potential == HIGH_LEVEL)
Irq_param.event = GPIO_IRQ_EVT_FALLING_EDGE;
Irq_param.callback = GPIO_Button_Cb; ---- 中断回调
Irq_param.arg = (void *)id;
GPIO_Button_IO button = Button_Reg[id];
HAL_GPIO_EnableIRQ(button.button_Port, ---- 使能中断
button.button_Pin, &Irq_param);
return COMP_OK;
}
static void GPIO_Button_Cb(void *arg)
{
uint32_t id = (uint32_t)arg;
if (id >= Button_Num)
return;
if (Button_Irq_Edge[id] == GPIO_IRQ_EVT_FALLING_EDGE) { ------------- 由1.2 方法负责注册 gpio_button_cb
Button_Irq[id].buttonCallBack(Button_Irq[id].arg, GPIO_IRQ_EVT_FALLING_EDGE);
Button_Irq_Edge[id] = GPIO_IRQ_EVT_RISING_EDGE;
} else {
Button_Irq[id].buttonCallBack(Button_Irq[id].arg, GPIO_IRQ_EVT_RISING_EDGE);
Button_Irq_Edge[id] = GPIO_IRQ_EVT_FALLING_EDGE;
}
GPIO_IrqParam Irq_param;
Irq_param.event = Button_Irq_Edge[id];
Irq_param.callback = GPIO_Button_Cb;
Irq_param.arg = (void *)id;
GPIO_Button_IO button = Button_Reg[id];
HAL_GPIO_EnableIRQ(button.button_Port, --- 下面分析1.1.5
button.button_Pin, &Irq_param);
}
void HAL_GPIO_EnableIRQ(GPIO_Port port, GPIO_Pin pin, const GPIO_IrqParam *param)
{
uint32_t regIdx;
uint32_t bitShift;
GPIO_IRQ_T *gpiox;
GPIO_Private *gpioPriv;
IRQn_Type IRQn;
unsigned long flags;
flags = HAL_EnterCriticalSection();
if (port == GPIO_PORT_A) {
gpioPriv = gGPIOAPrivate; ---- 共享数据
IRQn = GPIOA_IRQn;
} else if (port == GPIO_PORT_B) {
gpioPriv = gGPIOBPrivate;
IRQn = GPIOB_IRQn;
} else {
HAL_ERR("Invalid port %d for IRQ\n", port);
return;
}
gpiox = GPIO_GetIRQInstance(port);
/* set callback */
gpioPriv[pin].callback = param->callback; --- 操作共享数据, 回调 GPIO_Button_Cb
gpioPriv[pin].arg = param->arg;
/* set IRQ trigger mode */
GPIO_GET_REG_IDX_SHIFT(regIdx, bitShift, pin, GPIO_IRQ_EVT_BITS);
HAL_MODIFY_REG(gpiox->IRQ_MODE[regIdx],
GPIO_IRQ_EVT_MASK << bitShift,
(param->event & GPIO_IRQ_EVT_MASK) << bitShift);
if (GPIO_IsPendingIRQ(gpiox, pin)) {
GPIO_ClearPendingIRQ(gpiox, pin);
}
GPIO_EnableIRQ(gpiox, pin);
HAL_NVIC_SetPriority(IRQn, NVIC_PERIPHERAL_PRIORITY_DEFAULT);
HAL_NVIC_EnableIRQ(IRQn);
HAL_ExitCriticalSection(flags);
}
/**
* @brief Initialize the specified GPIO
* @param[in] port GPIO port
* @param[in] pin GPIO pin number
* @param[in] param Pointer to GPIO_InitParam structure
* @return None
*/
void HAL_GPIO_Init(GPIO_Port port, GPIO_Pin pin, const GPIO_InitParam *param)
{
uint32_t regIdx;
uint32_t bitShift;
GPIO_CTRL_T *gpiox;
unsigned long flags;
flags = HAL_EnterCriticalSection();
if (gGPIOUsedCnt++ == 0) {
HAL_CCM_BusEnablePeriphClock(CCM_BUS_PERIPH_BIT_GPIO);
}
gpiox = GPIO_GetCtrlInstance(port);
/* set working mode (function) 工作模式*/
GPIO_GET_REG_IDX_SHIFT(regIdx, bitShift, pin, GPIO_CTRL_MODE_BITS);
HAL_MODIFY_REG(gpiox->MODE[regIdx],
GPIO_CTRL_MODE_MASK << bitShift,
(param->mode & GPIO_CTRL_MODE_MASK) << bitShift);
/* set driving 驱动能力*/
GPIO_GET_REG_IDX_SHIFT(regIdx, bitShift, pin, GPIO_CTRL_DRIVING_BITS);
HAL_MODIFY_REG(gpiox->DRIVING[regIdx],
GPIO_CTRL_DRIVING_MASK << bitShift,
(param->driving & GPIO_CTRL_DRIVING_MASK) << bitShift);
/* set pull 上下拉*/
GPIO_GET_REG_IDX_SHIFT(regIdx, bitShift, pin, GPIO_CTRL_PULL_BITS);
HAL_MODIFY_REG(gpiox->PULL[regIdx],
GPIO_CTRL_PULL_MASK << bitShift,
(param->pull & GPIO_CTRL_PULL_MASK) << bitShift);
HAL_ExitCriticalSection(flags);
}
static void gpio_button_cb_init()
{
GPIO_Button_Irq irq;
irq.arg = (void *)GPIO_BUTTON_0;
irq.buttonCallBack = gpio_button_cb; ----------- 回调 gpio_button_cb 1.2.2
DRV_GPIO_ButtonCallBackRegister(GPIO_BUTTON_0, &irq); ----- 1.2.3
irq.arg = (void *)GPIO_BUTTON_1;
DRV_GPIO_ButtonCallBackRegister(GPIO_BUTTON_1, &irq);
}
static void gpio_button_cb(void *arg, GPIO_IrqEvent Irq_Edge)
{
uint32_t id = (uint32_t)arg;
if(Irq_Edge == GPIO_IRQ_EVT_FALLING_EDGE) { // press event
Gpio_Button_Event = GPIO_BUTTON_PRESS_EVENT; ----------- 更新共享数据
Gpio_Button_Combination += gpio_button_value(id);
DRV_GPIO_BUTTON_CTRL_DBG("%s, %d, press event; gpio_button_combination = %d\n",
__func__, __LINE__, Gpio_Button_Combination);
} else { //release event
Gpio_Button_Event = GPIO_BUTTON_RELEASE_EVENT; ----------- 更新共享数据
Gpio_Button_Combination -= gpio_button_value(id);
DRV_GPIO_BUTTON_CTRL_DBG("%s, %d, release event; gpio_button_combination = %d\n",
__func__, __LINE__, Gpio_Button_Combination);
}
}
void DRV_GPIO_ButtonCallBackRegister(uint32_t button_id, GPIO_Button_Irq *irq)
{
Button_Irq [button_id].buttonCallBack = irq->buttonCallBack; ---- 上面的 gpio_button_cb 回调
Button_Irq [button_id].arg = irq->arg;
}
在 project/common/startup/gcc/startup.s 中定义了中断入口地址
.word GPIOA_IRQHandler
.word GPIOB_IRQHandler
并且
/*******************************************************************************
*
* Provide weak aliases for each Exception handler to the Default_Handler.
* As they are weak aliases, any function with the same name will override
* this definition.
*
*******************************************************************************/
.weak GPIOA_IRQHandler
.thumb_set GPIOA_IRQHandler,Default_Handler
.weak GPIOB_IRQHandler
.thumb_set GPIOB_IRQHandler,Default_Handler
基于上述机制,查找自定义的 GPIOA_IRQHandler
void GPIOA_IRQHandler(void)
{
GPIO_IRQHandler(GPIOA_IRQ, GPIOA_PIN_NUM, GPIO_PINS_MASK(GPIOA_PIN_NUM), gGPIOAPrivate);
}
/*
* IRQ handling
*/
static void GPIO_IRQHandler(GPIO_IRQ_T *gpiox, uint32_t pinNum, uint32_t pinMask, GPIO_Private *priv)
{
uint32_t i;
uint32_t irqStatus;
uint32_t isPending;
irqStatus = gpiox->IRQ_STATUS & gpiox->IRQ_EN & pinMask; /* get pending bits */
gpiox->IRQ_STATUS = irqStatus; /* clear pending bits */
for (i = GPIO_PIN_0; i < pinNum && irqStatus != 0; ++i) {
isPending = irqStatus & HAL_BIT(0);
if (isPending && priv[i].callback) { ---- 回调到 gGPIOAPrivate 中注册的 GPIO_Button_Cb
priv[i].callback(priv[i].arg);
}
irqStatus >>= 1;
}
}
typedef struct {
GPIO_BUTTON_EVENT event;
GPIO_BUTTON_ID button_Id;
} Gpio_Button_Report;
typedef struct {
uint32_t button_Id;
uint32_t button_Value;
uint32_t short_Press_Hold_Time_Ms;
uint32_t long_Press_Hold_Time_Ms;
Gpio_Button_Repeat *repeat_Mode;
}Gpio_Button_Info;
Gpio_Button_Repeat Button_1_Repeat = {700, 10};
static Gpio_Button_Info Gpio_Button_Register[GPIO_BUTTON_NUM] = { --- 与 adc button 机制类似
/*button_0*/
{GPIO_BUTTON_0, (1 << GPIO_BUTTON_0), 10, 0, NULL},
/*button_1*/
{GPIO_BUTTON_1, (1 << GPIO_BUTTON_1), 10, 0, &Button_1_Repeat},
};
void gpio_button_ctrl_task(void *arg)
{
DRV_GPIO_BUTTON_CTRL_DBG("button_ctrl_task\n");
uint32_t button_press_time = 0;
Gpio_Button_Info *button = NULL;
while (button_ctrl_run) {
Gpio_Button_Report report = gpio_button_report(); ----- (获取底层按键中断刷新的按键信息)后面分析 1.3.2
if (report.event == GPIO_BUTTON_PRESS_EVENT) { ---- 按下 事件
if (report.button_Id < GPIO_BUTTON_NUM) {
DRV_GPIO_BUTTON_CTRL_DBG("%s, press button[%d]\n",
__func__, report.button_Id);
button_press_time = OS_JiffiesToMSecs(OS_GetJiffies()); ----- 获取按下的时间点
button = &Gpio_Button_Register[report.button_Id]; ----- 对应的预制的按键信息
} else {
DRV_GPIO_BUTTON_CTRL_DBG("%s, press button[null]\n",
__func__);
button = NULL;
continue;
}
} else if (report.event == GPIO_BUTTON_RELEASE_EVENT) { ---- 释放 事件
DRV_GPIO_BUTTON_CTRL_DBG("%s, release button[%d]\n",
__func__, report.button_Id);
button = &Gpio_Button_Register[report.button_Id];
gpio_button_short_press(button, button_press_time); ----- 短按 1.1.6
gpio_button_release_cmd (button); ----- 释放 1.3.7
button = NULL;
Button_Func_Is_Trigger = 0;
}
if (button != NULL)
gpio_button_check(button, button_press_time); ---- 后面分析 1.3.4
OS_MSleep(10);
}
OS_ThreadDelete(&g_button_ctrl_thread);
}
static Gpio_Button_Report gpio_button_report()
{
Gpio_Button_Event_Info event = gpio_button_event_handle();
Gpio_Button_Report report = {GPIO_BUTTON_NULL_EVENT, GPIO_BUTTON_NUM};
static uint32_t button_value = 0;
int i = 0;
if (event.event == GPIO_BUTTON_PRESS_EVENT) {
if (button_value != event.button_Value) {
report.event = GPIO_BUTTON_PRESS_EVENT;
for(i = 0; i < GPIO_BUTTON_NUM; i++) {
if(event.button_Value == Gpio_Button_Register[i].button_Value) {
button_value = event.button_Value;
report.button_Id = Gpio_Button_Register[i].button_Id;
return report;
}
}
report.button_Id = GPIO_BUTTON_NUM;
}
} else if (event.event == GPIO_BUTTON_RELEASE_EVENT) {
if ((button_value & event.button_Value) < button_value) {
for(i = 0; i < GPIO_BUTTON_NUM; i++) {
if(button_value == Gpio_Button_Register[i].button_Value) {
report.event = GPIO_BUTTON_RELEASE_EVENT;
report.button_Id = Gpio_Button_Register[i].button_Id;
}
}
button_value = 0;
}
}
return report;
}
typedef struct {
GPIO_BUTTON_EVENT event;
uint32_t button_Value;
} Gpio_Button_Event_Info;
typedef enum {
GPIO_BUTTON_PRESS_EVENT,
GPIO_BUTTON_RELEASE_EVENT,
GPIO_BUTTON_NULL_EVENT,
}GPIO_BUTTON_EVENT;
static Gpio_Button_Event_Info gpio_button_event_handle()
{
Gpio_Button_Event_Info button_event;
button_event.event = GPIO_BUTTON_NULL_EVENT;
button_event.button_Value= 0;
if (Gpio_Button_Event == GPIO_BUTTON_PRESS_EVENT) { --------- 该共享数据 在 gpio_button_cb 更新
button_event.event = GPIO_BUTTON_PRESS_EVENT;
button_event.button_Value = Gpio_Button_Combination;
} else if (Gpio_Button_Event == GPIO_BUTTON_RELEASE_EVENT) {
button_event.event = GPIO_BUTTON_RELEASE_EVENT;
button_event.button_Value = Gpio_Button_Combination;
}
Gpio_Button_Event = GPIO_BUTTON_NULL_EVENT;
return button_event;
}
static void gpio_button_check(Gpio_Button_Info *button, uint32_t button_press_time)
{
uint32_t os_time = OS_JiffiesToMSecs(OS_GetJiffies());
gpio_button_repeat(button, button_press_time, os_time); -------- 重复检测
gpio_button_long_press(button, button_press_time, os_time); ---- 长按检测
}
static void gpio_button_repeat(Gpio_Button_Info *button, uint32_t button_press_time, uint32_t os_time)
{
static uint32_t last_d_time = 0;
if (button->repeat_Mode != NULL) {
uint32_t repeat_hold_time = button->repeat_Mode->repeat_Press_Hold_Time_Ms;
uint32_t repeat_period = button->repeat_Mode->repeat_Period_Ms;
uint32_t d_time = gpio_button_d_time(button_press_time, os_time); ----- 按下之后经过的ms数
if (d_time >= repeat_hold_time) { -------------- > 700ms 则认为重复按下
Button_Func_Is_Trigger = 1;
if (d_time - last_d_time >= repeat_period) { ----- 重复周期 10ms
GPIO_Button_Cmd_Info * p = &gpio_button_cmd; ----- 更新共享数据
p->cmd = GPIO_BUTTON_CMD_REPEAT;
p->id = button->button_Id;
gpio_button_send_vkey(p); ----- 推送事件到g_sys_queue 中,以备感兴趣的订阅者recv
last_d_time = d_time;
}
}
}
}
static void gpio_button_short_press(Gpio_Button_Info *button, uint32_t button_press_time)
{
if (Button_Func_Is_Trigger == 0) {
uint32_t os_time = OS_JiffiesToMSecs(OS_GetJiffies());
uint32_t d_time = gpio_button_d_time(button_press_time, os_time);
if (d_time >= button->short_Press_Hold_Time_Ms) { ----------- 10ms
GPIO_Button_Cmd_Info * p = &gpio_button_cmd; ----------- 共享数据更新
p->cmd = GPIO_BUTTON_CMD_SHORT_PRESS;
p->id = button->button_Id;
gpio_button_send_vkey(p); --------- 推送短按事件到 g_sys_queue 中,以备感兴趣的订阅者recv
}
}
static void gpio_button_release_cmd (Gpio_Button_Info *button)
{
if (Button_Func_Is_Trigger) {
GPIO_Button_Cmd_Info * p = &gpio_button_cmd;
p->cmd = GPIO_BUTTON_CMD_RELEASE;
p->id = button->button_Id;
gpio_button_send_vkey(p); --------- 推送短按事件到 g_sys_queue 中,以备感兴趣的订阅者recv
}
}