|
Multi-Threaded Tests for nRF7002 DK and nRF9151 DK Boards in Zephyr RTOS.
В статье рассказано о работе плат nRF7002 DK и nRF9151 DK в многопоточных тестах в Zephyr RTOS.
Из документации известно, что nRF7002 DK содержит две системаы на кристалле (SoC) nRF5340, каждая из которых имеет по два ядра Arm® Cortex®-M33.
Один чип (SoC) используется как хост-микроконтроллер (host microcontroller), второй чип (отладочный) служит для программирования и отладки приложения.
Одно ядро хост-микроконтроллера предназначено для выполнения прикладных программ (прикладной процессор),
другое (сетевой процессор) обеспечивает работу протоколов Bluetooth, Thread, Zigbee и других.
Комплект разработчика nRF9151 DK имет один процессор Arm Arm® Cortex®-M33 работающий на частоте 64 МГц.
Исходные коды тестов основаны на публикациях в GitHub от компании Nordic Semiconductor.
На рисунке 1 показаны исходный код и результат первого теста на плате nRF9151 DK. Код содержит два потока thread0_id и thread1_id с одинаковым приоритетом.
Потоки созданы статически.
Каждый поток (задача в терминах FreeRTOS) имеет функцию потока void thread0(void) строка 11 и void thread1(void) строка 16 соответственно.
Для вычисления времени работы потоков использованы функции time_stamp = k_uptime_get() и delta_time = k_uptime_delta(&time_stamp).
Первая из них запоминает время старта потока, вторая вычисляет время работы потока.
Между этими функциями вызывается функция k_msleep(20). Функция printk() выводит на экран сообщения о времени работы каждого потока.
Несколько слов о потоках и функции k_msleep(). В документации сказано:
"В любой момент времени поток может находиться в одном из следующих состояний: выполняется (Running), готов к выполнению (Runnable), не готов к выполнению (Non-runnable).
Планировщик (Scheduler) не включает «Non-runnable» поток в алгоритм планирования. k_sleep() изменяет состояние потока с «Running» на «Non-runnable» до истечения тайм-аута, а затем изменит его на «Runnable».
Это означает, что поток не будет кандидатом в алгоритме планировщика до истечения тайм-аута."
На рисунке 2 показаны исходный код и результат второго теста на плате nRF7002 DK.
Здесь в состав каждого потока включена функция static inline void emulate_work().
Эта функция эмулирует работу процессора. В состав функции входит цикл оператора for от 0 до 300000. Функция k_sleep(20) перенесена в конец цикла.
На рисунке 3 показаны исходный код и результат третьего теста на плате nRF7002 DK. В тесте создаются и запускаются потоки thread0_id и thread1_id с приоритетами 2 и 3 соответственно.
Кроме того, в строке 44 функцией k_work_queue_start() запускается поток очереди задач (Workqueue threads) с приоритетом 4.
Вместо выполнения функции emulate_work() в цикле while, эта функция отправляется как элемент задания в очередь задач, используя функцию k_work_submit_to_queue() (строка 50).
В документации на Zephyr RTOS Workqueue определяется так:
«Workqueue - это объект ядра, который использует выделенный поток для обработки рабочих элементов (work items) по принципу "первый пришел - первый вышел" (FIFO).
Каждый рабочий элемент обрабатывается путем вызова функции, указанной в рабочем элементе.
Рабочая очередь обычно используется ISR (Interrupt Service Routine) или потоком с высоким приоритетом для передачи несрочной обработки потоку с более низким приоритетом, чтобы не влиять на обработку, зависящую от времени.»
1. Тест № 1.
Исходный код первого теста.
Вывод первого теста.
Рисунок 1.
Как работает первый тест? Сначала запускается функция void thread0(void). Затем, в цикле while(1) вызывается функция k_msleep(20).
Это приводит к тому, что поток "засыпает" и планировщик переводит первый поток в состояние "Non-runnable".
Далее планировщик запустит на выполнение второй поток - функцию thread1(void).
Функция k_msleep(20) во втором потоке переведет и второй поток в состояние "Non-runnable".
Через 20 мс. после старта "проснется" первый поток и выведет на экран длительность "сна".
Планировщик переведет первый поток в состояние "Runnable" и запустит его на выполнение.
Далее все переходы состояний первого и второго потоков будут повторяться.
2. Тест № 2.
Исходный код второго теста.
Вывод второго теста.
Рисунок 2.
Как работает второй тест? Первой запускается функция первого потока void thread0(void),
затем в строке 23 функция emulate_work().
Примерно через 87 мс. функция закончит работу, после чего будут вызваны функции k_uptime_delta(&time_stamp), printk(), k_msleep(20).
Вызов k_msleep(20) приведет к тому, что первый поток "заснет" на 20 мс.
Далее планировщик запустит на выполнение второй поток - функцию thread1(void).
Работа второго потока аналогична работе первого.
Через 20 мс. "проснется" первый поток, однако до окончания работы второго потока ~ (77 mc.) начало нового цикла первого потока будет задержано.
3. Тест № 3.
Исходный код третьего теста.
Вывод третьего теста.
Рисунок 3.
Работа третьего теста хорошо описана в курсе (GitHub repository for this course) от компании Nordic Semiconductor.
В тестах курса используется плата nRF54L15 DK работающая на частоте 128 MHz.
Выходные данные работы потоков из курса Nordic Semiconductor и теста №3 совпадают по смыслу.
Распечатка теста показывает, что thread0 не затрачивает время на обработку функции emulate_work().
Однако продолжительность работы thread1 в тесте №3 в два раза больше чем у nRF54L15 DK.
Вероятно, это свидетельствует о том, что тестируемая плата работает на частоте 64 МГц.
4. Отладка и графическое отображение работы системы.
Приведенные в статье тесты очень просты. В реальных проектах применяют и другие примитивы выполнения (execution primitive).
Например:
cooperative threads,
Meta-IRQ,
system threads,
logging threads,
обработчики прерываний (ISR),
очереди сообщений (Message Queue).
Для глубокого изучения оборудования от Nordic Semiconductor и Zephyr RTOS предлагается курс
Beyond the basics (За пределами основ).
Этот курс содержит более сложные примеры. В качестве инструмента для визуального отображения и отладки работы системы в курсе рекомендуется
nRF Connect for VS Code.
Вот пример проекта с применением окна просмотра потоков.
Тесты можно загрузить.
Консультации через e-mail: veresov@jdesign.ru или телефон: +7 921-215-45-70.
|
