Увидел здесь.
И поэтому все американские претензии на Гренландию и вообще любые телодвижения на Севере — это не что-то далёкое. Это то, что происходит на нашем заднем дворе.
И туда, между прочим, лезут жулики!
Блог обо всём.
А вот программные таймеры FreeRTOS-овские меня немножечко разочаровали.
Для реализации таймерных callback-функций есть серьезные ограничения: они должны быть быстрыми и ни в коем случае не должны входить в состояние блокировки (например ожидание мьютекса). То есть там практически такие же ограничения, как и для функций обработчиков прерываний.
С одной стороны, оно понятно, почему так (следствие способа реализации этих самых таймеров). А с другой стороны — доставляет неудобства, т.к. фактически действия «по таймеру» приходится делать не в самой callback-функции таймера, а где-то ещё.
Ну хорошо.
Для моих целей пришлось сделать класс-обертку для реализации моей версии таймеров. У меня единственной задачей таймера является в нужный момент установить нужные флажки в указанной «группе событий» (термин FreeRTOS) — и всё. А уже другая задача будет ждать соответствующего флажка и при его обнаружении делать всё что надо. (На слух всё это звучит «не очень», но реализация получилась довольно удобная и довольно универсальная.)
В результате от «таймеров на millis()» я избавился везде, где это было целесообразно. При этом код, как ни странно, стал более простым и более понятным.

Всего получилось 15 задач.
И все эти задачи раньше приходилось реализовывать вручную, на стандартных костылях Arduino-style (функции tick(), «таймеры на millis()» и всё остальное, в результате чего код становился трудно читаемым).
С переходом на нормальные задачи код стал заметно проще. Всем ардуинщикам очень рекомендую по возможности перебираться на FreeRTOS. Благо, она есть для всего уже.

Стало мне вдруг интересно, раскидывает ли FreeRTOS задачи по разным ядрам контроллера (в RP2040 их два).
Проделал лабораторную работу.
В баяне V3 у меня сейчас используется 11 задач. Я в них добавил кусочек кода, который выставляет флажок в разных местах, в зависимости от того, на каком ядре выполняется задача. Ну и сделал вывод флажков на экранчик.
Оказывается, оно действительно использует оба ядра. Причём не так, что задачи запускаются на конкретном ядре, и потом на нём остаются. Они вполне себе могут перемещаться между ядрами. Видимо, в зависимости от загрузки ядер в каждый конкретный момент.
Очень интересно это всё.

В общем, лекарство от обозначенной в предыдущей заметке болезни выглядит так (см. рис. 1).
В разрыв SPI-цепей CS и MISO впаивается вот такая «пилюля» (асинхронный буфер с 3-мя состояниями выхода). И переводит линию MISO в Z-состояние когда CS = 1.
Надо только в термоусадку эту страсть спрятать.
P.S. Спрятал — см. рис. 2
P.P.S. Вторая пилюля, запаянная на шлейф левой клавиатуры, тоже работает как ожидалось: обе клавиатурные RP2040 не мешают друг другу (до того они не работали вместе на одной шине SPI) и не конфликтуют с SD-картой.
Я тут потихоньку перевожу прошивку своего баяна на FreeRTOS. Начинал с самого простого и очевидного и продвигался по мере роста сложности задачи.
Вчера оформил в виде отдельной задачи проигрывание MIDI-файлов автоаккомпанемента. Понятно, что в результате эта проигрывалка оказалась написана не так, как если бы её с нуля писать под FreeRTOS — в этом случае наверняка что-то было бы по-другому. Но я решил революций не устраивать, и вместо полного переписывания сделал адаптацию.
В соответствующем классе, в отличие от всех остальных, которые уже были переведены на FreeRTOS, хранится довольно много данных (всякие настройки, стейт-машины, всякие вспомогательные данные и т.п.). Наружу из класса торчат публичные функции-члены, с помощью которых внешняя задача управляет процессом (запускает, останавливает, меняет т емп, меняет мелодию и т.п.). С точки зрения класса этого проигрывателя, управляющие воздействия — это изменение внутренних данных. А есть ещё сама задача проигрывания MIDI-файла. Она эти самые внутренние данные «использует». Раньше, когда весь код баяна выполнятся в контексте одной задачи (главный цикл loop()), управляющие воздействия не конфликтовали с проигрыванием, т.к. выполнялись последовательно — т.е. сначала, при необходимости, что-то менялось во внутренних данных (например менялся темп воспроизведения), а затем проходила очередная итерация воспроизведения, которая использовала уже измененные данные.
А тут управляющие воздействия будут проводиться в контексте другой задачи, т.е. может оказаться так, что внутренние потроха могут измениться в момент их использования функцией проигрывания. Т.е. появляется новый ресурс — «потроха MIDI-проигрывателя», доступ к которому в каждый момент времени должна иметь только одна задача. Т.е. потроха проигрывателя нужно просто защитить мьютексом. Так оно и было сделано.
Работает.
И правая половина работает, и левая (справа и слева на рис. 1 соответственно).
Нюанс заключается в том, что каждая половина может принимать и отправлять сообщения только тогда, когда от центрального модуля отключена другая. Не живут они обе на шине SPI одновременно.
Похоже, что чуда не произошло, и известная проблема с SPI-slave устройставми на RP2040 проявилась в полный рост. (RP2040, работая как SPI-slave, не переводит линию MISO в Z-состояние, когда SPI интерфейс неактивен.) Ничего не поделаешь, надо с этой проблемой бороться.
Придётся делать дополнительные мини-платы «SPI адаптеров» для правой и левой плат. И лепить на них асинхронные буферы с тремя состояниями на выходе. Знать бы про это заранее — я бы на самих платах такие буферы предусмотрел. Там дел-то на 3 копейки, и подключение элементарное.
Ничего не поделаешь, таковы издержки разработки, когда проблема может проявиться на поздней стадии, когда платы уже готовы.
Находясь под впечатлением от написания прошивки для платы активной клавиатуры под FreeRTOS, я решил, что и прошивку центральной платы тоже надо переводить на FreeRTOS, чтобы всё было «по красоте».
И хороший момент заключается в том, что переход можно делать постепенно, модуль за модулем. Потому что FreeRTOS-ное хозяйство отлично уживается с тем, что написано в традиционном «ардуинном» фреймворке.
Вот сегодня, например, я перевел на FreeRTOS-ные рельсы модуль драйвера SPI клавиатуры (т.е. клавиатуры, которая умеет присылать нажатия с измеренной velocity). А основная логика, включая автоаккомпанемент, продолжает нормально работать по-старому.
Так что баянчик будет переезжать на новую платформу в комфортных условиях.
И вообще, я теперь фанат FreeRTOS. Она прекрасна.

Осталось запаять датчики в клапанные окна.
По результатам запайки этой версии баяна я, пожалуй, поменяю своё отношение к SMD компонентам. Пожалуй, с проводными детальками больше геморроя при пайке. SMD, пожалуй, проще паять. Правда резюки и кондеры я беру большие: 1206. Мельче — категорически отказать.
P.S. Заодно, кстати, была доведена до условно-готового состояния прошивка клавиатур. Функционал реализован полностью, осталась мелкая подстройка всякого (при необходимости, по ходу дела).
Полный цикл опроса всех датчиков одной клавиатуры занимает 100 мкс. С учётом того, что при самом быстром нажатии на клавишу соответствующий рычаг пролетает из одного крайнего положения в другое примерно за 2 мс, получается, что за это время система успеет опросить состояние соответствующего датчика примерно 20 раз. Этого вполне достаточно для надёжной и точной регистрации времени нажатия. Собственно, эти тайминги практически не отличаются от тех. что были получены в прототипе, где я отрабатывал способ измерения времени.