Skip to content

K:04 (Qube): ввод замирает на ~1.3 с, зажатая клавиша уходит в автоповтор #16

Description

@AlexBSoD

Кратко

На K:04 с донглом Qube ввод периодически замирает целиком примерно на 1.3 секунды. Клавиша, которая была нажата в момент замирания, остаётся зажатой в HID-репорте, и хост уводит её в автоповтор — снаружи это выглядит как «залипла клавиша». Через ~1.3 с приходит release, и всё продолжается как ни в чём не бывало.

Проверено на стоковой прошивке 0.1.7 (тег v0.1.7), на чистом хосте, без стороннего софта.

Окружение

  • K:04 + донгл Qube, беспроводной режим, две половины
  • Прошивка 0.1.7 (стоковая, с сайта), vendor_id = 0xE126, product_id = 0x0071
  • Хост: Linux, ядро 7.1.8, донгл воткнут напрямую в порт материнской платы

Симптом

Мерил чтением /dev/input/event* напрямую — сырые evdev-события, минуя раскладку, IME и любые прослойки.

Эпизод целиком:

14:30:24.346   код 36 (J)  нажатие
14:30:24.602   код 36      автоповтор ядра
14:30:24.636   код 36      автоповтор
   ...                     всего 32 повтора, ровно по 34 мс
14:30:25.660   код 36      автоповтор
14:30:25.682   код 36      отпускание   ← через 1336 мс после нажатия

Ключевой момент: между нажатием и отпусканием прошло 1336 мс, и за всё это время с клавиатуры не пришло ни одного другого события. Я печатаю с интервалом 90–130 мс между клавишами, то есть за 1.3 с должно было прилететь около десяти событий. Их нет. Замирает не одна клавиша, а весь поток целиком.

Второй эпизод из того же лога, три минуты спустя:

14:33:24.225   код 22      нажатие     Δ113 мс
14:33:24.330   код 22      отпускание  Δ105 мс
14:33:24.435   код 38 (L)  нажатие     Δ105 мс   ← ритм печати
14:33:24.690   код 38      автоповтор ×33, по 34 мс
14:33:25.5..   код 38      отпускание — 1.09 с

Клавиша ушла в автоповтор посреди слова, в темпе 105 мс между предыдущими нажатиями. Букву «l» на секунду никто не зажимает специально.

Для сравнения — нормальный участок того же лога:

14:30:23.303   код 57  нажатие     Δ 83 мс
14:30:23.305   код 33  нажатие     Δ  2 мс
14:30:23.363   код 33  отпускание  Δ 58 мс
14:30:23.468   код 57  отпускание  Δ105 мс
14:30:23.670   код 14  нажатие     Δ202 мс
14:30:23.745   код 14  отпускание  Δ 75 мс

Статистика

На стоковой 0.1.7: окно 19.9 минуты активной печати, 1654 события, два таких эпизода — 1.06 с и 1.09 с.

Оговорка про метод: так фиксируются только те замирания, при которых в момент заморозки была зажата клавиша, дающая автоповтор. Замирания в паузе между нажатиями этим способом не видны вообще, так что два эпизода за 20 минут — нижняя граница, а не оценка частоты.

По более ранним замерам другим методом (по паузе с последующим залпом накопленных событий, 58+ эпизодов за несколько часов печати): длительность 0.7–4.3 с, медиана около 1350 мс, частота порядка 70–100 эпизодов за час активной печати.

Ещё наблюдение: замирания бывают одновременными для обеих половин. Из 28 эпизодов в 12 после разморозки события приходили сразу с обеих половин одним залпом. То есть замирает что-то общее, а не связь с одной конкретной половиной.

Что исключено измерением

Всё перечисленное проверено на практике, а не рассуждением.

  • Версия прошивки. Проверены четыре разные сборки плюс стоковая 0.1.7. Медиана замирания во всех 1336–1378 мс, различия в частоте в пределах статистического шума.
  • Стороннее ПО на хосте. Демон, который слал донглу raw-HID пакеты (часы, раскладка), был полностью остановлен на всё время замера. Разницы нет.
  • Соседняя 2.4 ГГц периферия. Приёмник Logitech Unifying физически вынимался из порта. Замирания остались.
  • USB-хаб и питание по USB. Донгл переехал из хаба напрямую в порт материнской платы. Замирания остались, оба эпизода выше сняты уже на прямом порту.
  • Хост. Отдельный детектор дрейфа планировщика замерял отклонение 10-миллисекундного сна каждую минуту: worst = 0 ms в каждой минуте, включая ту, в которой было замирание ввода на 3.5 с.
  • USB-уровень. В момент замирания в dmesg пусто: ни ошибок xhci, ни таймаутов, ни -71/-110, ни реконнектов. С точки зрения хоста устройство просто молчит, а потом снова начинает говорить.

Подозрения

Дальше — уже гипотезы, а не измерения. Проверить их у меня пока не получилось, поэтому выкладываю как есть.

1. Приоритеты прерываний в макро-пути.

rmk-macro/src/codegen/chip/bind_interrupt.rs:243-246 отдаёт MPSL её штатные прерывания:

EGU0_SWI0 => ::nrf_sdc::mpsl::LowPrioInterruptHandler;
RADIO     => ::nrf_sdc::mpsl::HighPrioInterruptHandler;
TIMER0    => ::nrf_sdc::mpsl::HighPrioInterruptHandler;
RTC0      => ::nrf_sdc::mpsl::HighPrioInterruptHandler;

При этом rmk-macro/src/codegen/chip/chip_init.rs:146-152 для nRF52 генерирует конфиг, в котором приоритеты не выставляются вообще:

let mut config = ::embassy_nrf::config::Config::default();
#dcdc_config
let p = ::embassy_nrf::init(config);

То есть gpiote_interrupt_priority и time_interrupt_priority остаются на значении по умолчанию — P0, на том же уровне, который MPSL держит за своими RADIO/TIMER0/RTC0.

Показательно, что в самом репозитории требование известно: examples/use_rust/nrf52840/src/main.rs:41-43 явно выставляет

config.gpiote_interrupt_priority = ::embassy_nrf::interrupt::Priority::P3;
config.time_interrupt_priority = ::embassy_nrf::interrupt::Priority::P3;
::embassy_nrf::interrupt::USBD.set_priority(::embassy_nrf::interrupt::Priority::P2);

Но для всего, что собирается через #[rmk_central] / #[rmk_peripheral], эта настройка теряется.

Задержанные радио-прерывания объяснили бы наблюдаемое: и замирание всего потока сразу, и то, что обе половины замирают синхронно, и то, что длительность стабильно держится около 1.3 с независимо от версии прошивки.

2. Дисплей на Qube. На донгле SPIM3 регистрируется через add_interrupt! в keyboards/k04/src/qube.rs:20-22 и по той же причине оказывается на P0. Это единственная периферия на донгле, которая активно шевелит SPI на 8 МГц во время печати. Собрал себе безэкранный вариант донгла, чтобы это проверить, — как будут результаты, отпишусь здесь же.

3. Источник тактирования MPSL. Если MPSL работает от RC-осциллятора (±500 ppm), а не от кварца 32.768 кГц, окна радио плавают сильнее, чем могли бы. Не проверял, есть ли на платах кварц.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions