XR871 sdk evb_audio 的gpio button逻辑分析


Gpio Button


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");
}

1.1 DRV_Board_GPIO_Button_Cfg


1.1.1 DRV_Board_GPIO_Button_Cfg

/**
  * @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;
}

1.1.2 GPIO_ButtonInit

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, &param);

    Enable_GPIO_Button(id, button.default_Potential); ---- 下面分析1.1.3
    return COMP_OK;
}

1.1.3 Enable_GPIO_Button

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;
}

1.1.4 GPIO_Button_Cb

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);
}

1.1.5 HAL_GPIO_EnableIRQ

    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);
    }

1.1.6 HAL_GPIO_Init

    /**
     * @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);
    }

1.2 gpio_button_cb_init


1.2.1 gpio_button_cb_init

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);
}

1.2.2 gpio_button_cb

    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);
        }
    }

1.2.3 DRV_GPIO_ButtonCallBackRegister

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;
    }
}

1.3 gpio_button_ctrl_task


1.3.1 gpio_button_ctrl_task

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);
}

1.3.2 gpio_button_report

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;
}

1.3.3 gpio_button_event_handle

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;
}

1.3.4 gpio_button_check

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); ---- 长按检测
}

1.3.5 gpio_button_repeat

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;
            }
        }
    }
}

1.3.6 gpio_button_short_press

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
    }
}

1.3.7 gpio_button_release_cmd

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
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值