Знайомство: BBC micro:bit і mbed OS 5

Як зазначалося на geektimes, мікрокомп'ютер BBC micro:bit ще цієї весни почали розсилати британським школярам, а пару місяців тому він надійшов у вільний продаж за ціною від £13 за штуку.

Припустимо, micro:bit придбаний; що з ним робити далі? Я вирішив зробити з нього годинник, тому що мої наручні як раз зламалися.


Інструкція по використанню micro:bit зі старою версією mbed OS є на сайті Ланкастерського університету; але ARM два тижні тому випустила нову версію mbed OS 5, і з цією новою версією бібліотека підтримки microbit-dal «з коробки» не працює.

Наскільки я розумію, навіть в самому ARM ніхто ще не намагався використовувати mbed OS 5 на micro:bit; мені хотілося стати першим.

Для початку роботи потрібно встановити середовище розробки mbed CLI. Вона написана на Python (для роботи потрібна версія 2.7.6+), і поширюється за допомогою PyPI:

$ sudo pip install mbed-cli

Або, якщо ми працюємо на машині без прав root, і навіть без
pip
:

$ wget http://bootstrap.pypa.io/ez_setup.py
$ python ez_setup.py --user
$ ~/.local/bin/pip install virtualenv --user
$ ~/.local/bin/virtualenv venv
$ source venv/bin/activate
(venv) $ pip install mbed-cli

Крім цього, потрібно встановити компілятор GNU ARM Embedded. Якщо tarball з компілятором розпакований
/work/gcc-arm-none-eabi-5_4-2016q2/
, то він реєструється в mbed CLI командою

$ mbed config --global GCC_ARM_PATH /work/gcc-arm-none-eabi-5_4-2016q2/bin/

Тепер створюємо для нашого проекту робоче оточення:

$ mbed new mb_clock
$ cd mb_clock
$ mbed target NRF51_MICROBIT
$ mbed toolchain GCC_ARM
Якщо команда
mbed new
виконується з-під root і/або всередині venv, то вона сама доустановит в систему необхідні модулі Python. В іншому випадку, вона попросить виконати

$ sudo pip install -r mbed-os/requirements.txt
Наступний крок — додамо в наше робоче оточення бібліотеки підтримки micro:bit:

$ add mbed https://github.com/lancaster-university/microbit # перша ланкастерська бібліотека
$ add mbed https://github.com/tyomitch/microbit-dal # мій форк другий ланкастерской бібліотеки

У складі ланкастерской бібліотеки є асемблерний файл
CortexContextSwitch.s
, який поставляється в двох варіантах: для GNU as та armasm. Бібліотека для mbed OS 3 включала файл
CMakeLists.txt
, в якому був прописаний автоматичний вибір потрібного варіанту. На жаль, mbed OS 5 ігнорує
CMakeLists.txt
, так що варіант для GNU as доведеться вибрати вручну:

$ cp microbit-dal/source/asm/CortexContextSwitch.s.gcc microbit-dal/source/asm/CortexContextSwitch.s

Крім цього, з ланкастерской бібліотекою є ще кілька проблем:

  1. mbed OS 5 включає підтримку багатопоточності, тому код microbit-dal тепер виконується з «користувача» стеком (PSP), а не з «системним» (MSP), як в попередніх версіях mbed OS;

  2. системний API для роботи з BLE mbed OS 5 змінився;

  3. підтримка BLE в mbed OS 5 займає занадто багато пам'яті, і на micro:bit з його 16 КБ RAM вона просто не влазить;

  4. розмір стека за замовчуванням (2 КБ) занадто великий: з таким стеком в системі не залишається вільної пам'яті для динамічного виділення («купа»).
Перші дві проблеми виправлені в моєму форке ланкастерской бібліотеки; для третьої пропонується наступний низькотехнологічний воркараунд:

$ rm mbed-os/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_MCU_NRF51822/source/nRF5xn.cpp

Остання проблема вирішується параметрами компіляції: щоб купи вистачило для роботи microbit-dal, системний стек повинен бути розміром 512 байт або менше. (Обробників переривань, які ним користуються, вистачає і половини цього.)

Тепер найцікавіше — власне реалізація годин. В ній всього два нетривіальних моменту:

  • Для того, щоб відображати на дисплеї micro:bit розміром 5х5 світлодіодів по дві цифри одночасно, довелося творчо підійти до створення шрифту. Нуль я вирішив зробити у вигляді точки посередині знакомісця (схожим чином він виглядає арабських цифрах), вісімку — у вигляді двокрапки, за логікою «два нулі, один над іншим». Всі інші цифри впізнаються без жодного утруднення.

  • micro:bit немає енергонезалежних «годинника реального часу», тому час відраховується від початкового завантаження. Початкова відображуване значення задається у момент компіляції; після запуску, за допомогою двох кнопок micro:bit, відображуване час можна коригувати в ту або іншу сторону, з кроком в одну хвилину.
Лістинг
#include "MicroBit.h"

MicroBit uBit;

const uint8_t digit_bits[10][10] = {
{ 0, 0,
0, 0,
0, 1,
0, 0,
0, 0 },
{ 0, 1,
0, 1,
0, 1,
0, 1,
0, 1 },
{ 1, 1,
0, 1,
1, 1,
1, 0,
1, 1 },
{ 1, 1,
0, 1,
1, 1,
0, 1,
1, 1 },
{ 0, 1,
1, 1,
1, 1,
0, 1,
0, 1 },
{ 1, 1,
1, 0,
1, 1,
0, 1,
1, 1 },
{ 0, 1,
1, 0,
1, 0,
1, 1,
1, 1 },
{ 1, 1,
0, 1,
0, 1,
1, 0,
1, 0 },
{ 0, 0,
0, 1,
0, 0,
0, 1,
0, 0 },
{ 1, 1,
1, 1,
0, 1,
0, 1,
1, 0 }
};
MicroBitImage digits[] = {
MicroBitImage(2,5,digit_bits[0]),
MicroBitImage(2,5,digit_bits[1]),
MicroBitImage(2,5,digit_bits[2]),
MicroBitImage(2,5,digit_bits[3]),
MicroBitImage(2,5,digit_bits[4]),
MicroBitImage(2,5,digit_bits[5]),
MicroBitImage(2,5,digit_bits[6]),
MicroBitImage(2,5,digit_bits[7]),
MicroBitImage(2,5,digit_bits[8]),
MicroBitImage(2,5,digit_bits[9])
};

int started_at = 18*60+53;

void onButtonAClick(MicroBitEvent evt)
{ 
started_at--;
}

void onButtonBClick(MicroBitEvent evt)
{ 
started_at++;
}

int main()
{ 
uBit.init();
uBit.messageBus.listen(MICROBIT_ID_BUTTON_A, MICROBIT_BUTTON_EVT_CLICK, onButtonAClick);
uBit.messageBus.listen(MICROBIT_ID_BUTTON_B, MICROBIT_BUTTON_EVT_CLICK, onButtonBClick);

while(1) {
int cur_time = (started_at + uBit.systemTime() / 60000L) % (24*60);
int hours = cur_time / 60;
int minutes = cur_time % 60;
uBit.display.image.paste(digits[hours/10],0,0,0);
uBit.display.image.paste(digits[hours%10],3,0,0);
uBit.sleep(300);
uBit.display.image.paste(digits[minutes/10],0,0,0);
uBit.display.image.paste(digits[minutes%10],3,0,0);
uBit.sleep(300);
uBit.display.clear();
uBit.sleep(600);
}
}

Коли цей код збережений (скажімо, у файл
mb_clock.cpp
), весь проект можна скомпілювати, і завантажити на пристрій:

$ mbed compile -D __STACK_SIZE=512 -D ISR_STACK_SIZE=512 -D MICROBIT_BLE_ENABLED=0
$ cp ./.build/NRF51_MICROBIT/GCC_ARM/mb_clock.hex /media/MICROBIT

Готово!

При бажанні, для одержані годин можна змайструвати захисний корпус з баночки з-під вітамінів і термоклея:


Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.