Озвучення micro:bit v2 з використанням Zephyr RTOS
Я почав з простого бажання: перетворити BBC micro:bit v2 на диктофон за допомогою Zephyr RTOS. В підсумку я отримав щось зовсім інше. Ось історія про апаратні обмеження, ілюзії драйверів і математику, необхідну для того, щоб 5×5 світлодіодна матриця танцювала під людський голос.
Мрія: Мікро-Реєстратор
BBC micro:bit v2 – це справжня потужність. У нього є SoC nRF52833, MEMS-мікрофон і динамік. Зрозуміло, моїм першим інстинктом було: “Запишу аудіо і відтворю його”.
Я налаштував середовище Zephyr. Я сконфігурував АЦП. Я побудував систему кругового буфера.
І це спрацювало! Я міг бачити зміни значень RMS в консолі, коли говорив.
Але потім я спробував відтворити це.
Спроба 1: PWM “Динамік”
micro:bit не має ЦАП. У нього є п’єзо-магнітний зуммер, підключений до GPIO-піна. Щоб відтворити аудіо, мені довелося модуляціювати робочий цикл ШІМ, щоб підробити аналогову хвилю.
Ми пробували біт-бенг (занадто повільно). Я спробував стандартний API ШІМ Zephyr (занадто важко). Нарешті, я написав прямий драйвер апаратного забезпечення, використовуючи Nordic HAL і EasyDMA, щоб подавати зразки в периферію ШІМ без блокування ЦП.
Цей код “Технічно працює”, але “Аудіодисастер”
“`c
static void audio_hw_play(const int16_t *buf, size_t n) {
NRF_PWM_Type *pwm = (NRF_PWM_Type *)DT_REG_ADDR(DT_NODELABEL(pwm0));
// Міняємо 12-бітне аудіо на робочий цикл ШІМ
for (size_t i = 0; i < n; i++) {
int32_t duty = 500 + (buf[i] * 500) / 2048;
pwm_seq_buf[i] = (uint16_t)duty;
}
// Запускаємо послідовність DMA
pwm->SEQ[0].PTR = (uint32_t)pwm_seq_buf;
pwm->TASKS_SEQSTART[0] = 1;
}
“`
Результат? Це звучало, як білка, що застрягла в блендері. Я сповільнив такт. Це звучало, як демон, що застряг у блендері.
Осяяння: Вбудований компонент (MLT-8530) – це магнітний зуммер. Він фізично налаштований на резонанс на 2-4 кГц (пищики). Він не може відтворювати складні частоти людської мови. Я намагався зіграти симфонію на дверному зумері.
Отже, я змінив підхід. Якщо я не можу чітко чути аудіо, давайте переконаємось, що я можу його бачити.
Зміна: Звуковий рівнемір
Мета змінилася: створити “мікрофонний тестовий бар” у стилі Zoom на 5×5 світлодіодній матриці micro:bit.
Пастка #1: Фантомний PDM
Zephyr має відмінну підтримку PDM (модуляція щільності імпульсів) мікрофонів, які поширені на платах nRF52. Ми активували CONFIG_AUDIO_DMIC, налаштували пін-коди і зафлешили плату.
Але консоль видавала помилки:
[err] dmic_nrfx_pdm: Запитувана конфігурація не підтримується
Я провів години, налаштовуючи тактові частоти. 16 кГц? 15.625 кГц? 1.28 МГц? Нічого не спрацювало.
Отже, я відкрив схему.
Мікрофон на micro:bit v2 (Knowles SPU0410LR5H) НЕ є PDM. Це аналоговий мікрофон, підключений до P0.05 (AIN3).
Я намагався змусити цифровий драйвер спілкуватися з аналоговим контактом.
Виправлення: Я викинув драйвер DMIC і написав власний накладний файл дерева пристроїв для налаштування SAADC (АЦП послідовного наближення). Зверніть увагу на специфічний коефіцієнт підсилення: мікрофон має 1.65В постійної складової, тому стандартні налаштування підсилення відразу наситяться.
“`c
/* app.overlay */
&adc {
channel@3 {
reg = <3>; // AIN3
zephyr,gain = “ADC_GAIN_1_4”; // Діапазон до 2.4В покриває 1.65В постійної складової
zephyr,reference = “ADC_REF_INTERNAL”;
zephyr,acquisition-time =
zephyr,input-positive =
zephyr,resolution = <12>;
};
};
“`
Візуалізація: Зробимо світлодіоди танцювати
Тепер у мене були чисті аудіодані. Я хотів відобразити гучність на світлодіодах.
Пастка #2: Невидимий дисплей
Я розрахував гучність і відправив її на дисплей, використовуючи display_write. І… екран залишився чорним.
Стандартний драйвер дисплея Zephyr є загальним. Він очікує буфер пікселів. Я припустив 1 байт на піксель (25 байтів).
Але драйвер micro:bit упакований по бітах. Він очікує бітову карту, де 1 біт = 1 піксель. Відправивши 25 байтів, я відправляв “дані заголовка”, які виглядали як порожній простір для драйвера.
Отже, я виправив відображення буфера. 5 рядків = 5 байтів.
“`c
/* Правильне відображення бітової карти */
static void update_display(int level) {
uint8_t buf[5];
memset(buf, 0, sizeof(buf));
for (int i = 0; i < 5; i++) {
int row_index = 4 - i; // Інвертуємо, щоб заповнювати знизу вгору
if (i < level) {
buf[row_index] = 0x1F; // 0x1F = Бінарний 11111 (Усі світлодіоди в рядку УВІМКНЕНІ)
}
}
// Записуємо 5 байтів до контролера дисплея
display_write(display_dev, 0, 0, &desc, buf);
}
```
Остаточний бос: Фізика проти сприйняття
У мене були вогні. У мене був звук. Але коли я говорив, вогні ледве рухалися. Коли я подув у мікрофон, вони ненормально божеволіли.
Проблема:
RMS проти піку: Я розраховував RMS (середня енергія). Мова має короткі сплески енергії (приголосні), розділені тишею. Середнє значення 100 мс мови дає низьке число.
Фізика: Дування створює фізичний тиск вітру (величезна напруга). Мова створює маленькі повітряні коливання (маленька напруга).
Отже, я реалізував алгоритм "Підсилювач мови".
Виявлення піків: Замість RMS, ми обчислюємо Макс - Мін у буфері. Це миттєво фіксує "підвищення" вашого голосу.
Віднімання шумового фону: Ми емпірично з'ясували, що шумовий фон тиші становить ~94. Ми віднімемо це, щоб обнулити кімнату.
Цифрове підсилення: Ми множимо залишковий сигнал на 3. Це розтягує маленькі варіації людської мови, щоб заповнити повний діапазон 0-5 світлодіодної матриці.
```c
/* Логіка підсилювача мови */
int32_t raw_amp = calculate_peak_amplitude(sample_buffer, BUFFER_SIZE);
// 1. Віднімемо шумовий фон
int32_t signal = raw_amp - 94;
if (signal < 0) signal = 0;
// 2. Цифрове підсилення
int32_t boosted = signal * 3;
// 3. Відобразимо на світлодіодах з утриманням піку (гравітація)
if (boosted > 40) target_level = 5;
else if (boosted > 30) target_level = 4;
// … тощо
“`
Висновок
Я не зміг побудувати диктофон, але досягнув успіху в створенні надійного звукового рівнеміра.
Цей проект є відмінним прикладом вбудованої інженерії:
Не вірте припущенням (перевіряйте схему!).
Не боріться з апаратним забезпеченням (якщо це зуммер, не змушуйте його співати).
Математика – ваш друг (логарифмічне масштабування робить сенсори “природними”).
Вихідний код на Github
Повний вихідний код доступний нижче. Зафлеште його на свій micro:bit v2, плесніть у долоні і спостерігайте, як світлодіоди танцюють.
Відповідний PR до офіційного репозиторію Zephyr RTOS та новий приклад для micro:bit v2 скоро з’являться.
November 25, 2025 at 05:32PM

Залишити відповідь
Щоб відправити коментар вам необхідно авторизуватись.