lift_indicator_suite/bsp/button/README.md

5.9 KiB
Raw Permalink Blame History

bsp_button — тактовые кнопки (SWT6x6)

Чтение двух тактовых кнопок с программным дебаунсом. Предоставляет мгновенное сырое чтение, стабильное состояние и одноразовые события нажатия/отпускания.


Аппаратура

Идентификатор Сигнал Пин MCU Корпус GPIO Нажатие
BSP_BUTTON_1 TactBut1 GPIO_B1_14 C14 GPIO2[30] LOW
BSP_BUTTON_2 TactBut2 GPIO_B1_15 B14 GPIO2[31] LOW

Пины настроены в BOARD_InitPins() как INPUT с гистерезисом, без внутренней подтяжки (0x0100B0) — внешний pull-up к 3V3. bsp_button_init() не трогает GPIO — только сбрасывает внутреннее состояние модуля.


Архитектура

flowchart LR
    A["GPIO2[30] / GPIO2[31]"] --> B["GPIO_ReadPinInput()\nв bsp_button_poll()"]
    B --> C["счётчик дебаунса\n4 одинаковых сэмпла = 20 мс"]
    C --> D["stable state\nevt_pressed / evt_released"]
    D --> E["bsp_button_is_pressed()\nbsp_button_get_event_pressed()\nbsp_button_get_event_released()"]
  • Pollingbsp_button_poll() вызывается каждые 5 мс. Без прерываний.
  • Дебаунс — 4 одинаковых сэмпла подряд (BUTTON_DEBOUNCE_SAMPLES = 4, 4 × 5 мс = 20 мс). Глитч сбрасывает счётчик.
  • События — одноразовые флаги evt_pressed/evt_released, сбрасываются при первом обращении через get_event_*().

API

void bsp_button_init(void);
void bsp_button_poll(void);                          /* вызывать каждые 5 мс */

bool bsp_button_read(bsp_button_t btn);              /* сырое чтение без дебаунса */
bool bsp_button_is_pressed(bsp_button_t btn);        /* стабильное состояние */
bool bsp_button_get_event_pressed(bsp_button_t btn); /* одноразовое, сбрасывается при чтении */
bool bsp_button_get_event_released(bsp_button_t btn);

Быстрый старт

#include "bsp/button.h"

/* После board_hw_init(): */
bsp_button_init();

/* bare-metal — вызывать каждые 5 мс из tick-коллбэка: */
bsp_button_poll();

/* В main loop: */
if (bsp_button_get_event_pressed(BSP_BUTTON_1)) {
    /* однократное срабатывание по нажатию */
}

if (bsp_button_is_pressed(BSP_BUTTON_2)) {
    /* кнопка удерживается */
}

Startup check (bootloader) — сырое чтение до инициализации:

/* До bsp_button_init(), сразу после board_hw_init(): */
if (bsp_button_read(BSP_BUTTON_1)) {
    /* удерживается при старте → режим обновления */
}

Тестирование

Host unit-тесты

Категория Bbutton.c вызывает GPIO_ReadPinInput() из fsl_gpio.h. SDK-функция мокируется через fff. Stub fsl_gpio.h в tests/host/mocks/.

just build::test-host   # покрытие: init, дебаунс нажатия/отпускания,
                        # потребление событий, сброс при глитче, независимость кнопок

HIL-тест (интерактивный)

Оператор нажимает кнопки вручную по подсказкам. Не входит в hil-run.

just host::hil-button

C-прошивка: tests/target/hil_button/ — CLI через bsp_uart_host. pytest: tools/hil/04_test_button.py — помечен @pytest.mark.interactive.

Команда Ответ Описание
PING PONG Проверка канала
READ <idx> 1 / 0 Сырое состояние без дебаунса
STATE <idx> 1 / 0 Стабильное состояние после дебаунса
EVENT_P <idx> 1 / 0 get_event_pressed, сбрасывает флаг
EVENT_R <idx> 1 / 0 get_event_released, сбрасывает флаг

Интеграция

/* FreeRTOS — из задачи: */
vTaskDelay(pdMS_TO_TICKS(5));
bsp_button_poll();
if (bsp_button_get_event_pressed(BSP_BUTTON_1)) {
    xQueueSend(btn_queue, &btn_event, 0);
}

Логика длинного/короткого нажатия намеренно не реализована в BSP — это зона ответственности button_handler в tft_app:

bsp_button → button_handler → app (меню, навигация)

button_handler хранит press_start_ms, вызывает коллбэк с типом SHORT_PRESS / LONG_PRESS / REPEAT. Не зависит от железа — тестируется на хосте как категория A.


CMake

target_link_libraries(firmware_test PRIVATE
    bsp_board
    bsp_tick
    bsp_button
)

Зависимости модуля:

Зависимость Тип Описание
bsp_status PUBLIC bsp_status_t в публичном API
bsp_board PRIVATE Транзитивно: pin_mux.h, clock, SDK headers
sdk_gpio PRIVATE fsl_gpio.hGPIO_ReadPinInput()