С помощью дипсика я разобрался, как программировать эти ваши PIO.
Интересненько.
В приведённом примере PIO моргает светодиодом с частотой 1 Гц, а оба ядра микропроцессора в этом вообще никак не задействованы, и могут заниматься другими своими делами.
Как известно, в микроконтроллере RP2040 реализована интереснейшая штука: PIO — он же Programmable Input/Output block. Если совсем-совсем коротко, то внутри микроконтроллера (помимо собственных 2-х ядер) существуют ещё 4 (отдельно программируемых!) железки, которые могут работать независимо от основной программы микроконтроллера. Работать они могут в обоих направлениях: «шевелить ногами» на основе данных, поступающих из основной программы, или читать данные, приходящие на ноги (например по протоколу SPI или I2C), и давать основной программе уже готовые данные. (Насколько я понимаю, «аппаратные реализации» SPI и I2C интерфейсов микроконтроллера именно так и сделаны.*)
Если не совсем-совсем коротко, то вот эта статья даёт некоторое общее представление о том, что это такое.
Я давно хотел с этой темой разобраться. Интересно же. В результате — разобрался.
Но интересно то, КАК я разобрался.
Я загрузил в https://chat.deepseek.com даташит на RP2040, плюс ссылку на упомянутую статью, и начал Дипсика допрашивать. И это занятие оказалось очень продуктивным. ИИ отлично даёт ответы на разнообразные вопросы общего характера (типа «как сделан обмен данными между программой, выполняемой микроконтроллером, и Конечным Автоматом», т.е. State Machine. Или «какова разрядность регистров FIFO и выходных и входных регистров сдвига»).
И на примере практической задачи (чтение двух каскадов сдвиговых регистров 74HC165) Дипсик мне рассказал, как реализовать свой Конечный Автомат, который сам будет дёргать ногами Latch и CLK, читать данные из каскадов и укладывать их прямо в оперативную память через DMA (т.е. Direct Memory Access).
Т.е. из самой прошивки надо будет только сказать «прочитай данные из каскадов». PIO само всё сделает, и когда данные уже будут лежать в ОЗУ — вызовет прерывание. которое останется только обработать. При этом основные ядра микроконтроллера смогут заниматься другими делами, пока PIO само читает данные из регистров.
И я теперь не могу решить, что меня больше восхищает: то, как сделан PIO в контроллерах RP2040, или то, насколько быстро в этом получилось разобраться, используя ИИ. Без Дипсика я эту тему грыз бы не меньше чем пару дней.
Рис. 1
* — оказывается, нет. Стандартные интерфейсы (UART, I2C и SPI) сделаны в виде отдельных аппаратных блоков. И ресурсы PIO эти интерфейсы не используют.
Я добавлял чувствительность к скорости нажатия в свой MIDI-баян в том числе для того, чтобы естественно звучали вот такие штуки (по ссылке — короткий урок на тему «How to Play Beginner Cocktail Piano in 3 Steps»).
Однако, одной только чувствительности не хватило.
Для того, чтобы играть «сложные» аккорды левой рукой на баяне, нужно набирать нужные звуки, нажимая несколько кнопок «стандартных» аккордов. Вот здесь я выкладывал XLS-файл с калькулятором, помогающим определить, какие аккорды нужно нажимать, чтобы получился требуемый «сложный» аккорд.
Так вот, для того, чтобы играть аккорд Cmaj7 одновременно с басом (C), на левой руке не хватает пальцев. 🙂 Пианисты в таких случаях используют педаль. А значит и мне надо.
В результате я реализовал режим «педаль» в котором бас и аккорд продолжают звучать после отпускания кнопок до тех пор, пока не будет нажат новый бас, или пока не будет выключен режим «педаль».
В результате стало возможно получить вот такое звучание:
Теперь нужно привыкать нажимать кнопки с нужной силой. У баянистов такой привычки нет; в результате некоторые нажатия у меня пока получаются слишком слабые, а некоторые другие — слишком сильные.
Я тут решил попробовать добавить второй голос к «Ленивому Дику». Без второго голоса, всё-таки, чего-то не хватает.
За основу взял второй вариант записи. И просто наложил запись второго голоса.
В одном месте (на 1:13), конечно, первый и второй голоса плохо сочетаются, звучат фальшиво. Но я не понимаю, что я с этим могу поделать; пока оставлю так.
Как и обещал, публикую короткую техническую демонстрацию режима «соло». А данном случае солирующим является самый низкий голос (скрипка). Всё, что выше звучащего солирующего звука более чем на 1 тон, звучит как орган.
Перемещаюсь по клавиатуре вверх/вниз, чтобы было понятнее, в чём суть режима.
Всё, что планировал сделать, сделал. Электронную часть наладил; «странных необъяснимых глюков» не вижу уже 3 дня.
С точки зрения функционала, фантазия моя на данный момент иссякла. Сейчас есть всё, что нужно, для игры. Отличия от v2:
Основное — это чувствительность клавиатур к скорости нажатия клавиш. Само собой, «рояльной» точности управления звуком добиться не получилось, но три уровня звучания (тихо, средне. громко) получаются без проблем.
Добавлена функция «Акцент» для левой клавиатуры. Раньше можно было при нажатии баса или аккорда проигрывать звук ударного инструмента (любого выбранного). А сейчас, поскольку система может различить «обычное» и «сильное» нажатия, то на «сильные» нажатия баса и аккорда можно вешать дополнительные звуки. Например, при обычном нажатии будет звучать барабан, а при сильном ударе по клавише будет ещё звучать, например, тарелка.
Добавлена функция «соло» для правой клавиатуры. В двух вариантах «соло верхней нотой» и «соло нижней нотой». Этот режим позволяет совмещать звуки двух музыкальных инструментов. Например, если нажать «До» 1-й октавы, то одиночная нота будет звучать звуком текущего пресета. А если, удерживая «До», нажать ещё «Ми» и «Соль» 1-й октавы, то эти две ноты будут звучать уже тем звуком, который настроен в 6-м пресете текущего набора пресетов. (Техническую демонстрашку для этой функции я скоро запишу на видео, а вот сыграть что-нибудь, используя эту функцию, я пока не смогу, ибо недостаточно продвинут для того, чтобы играть подобное сходу, «из головы».)
Все пресеты, хранящиеся в энергонезависимой памяти EEPROM, теперь можно сохранить в виде резервной копии на SD-карту, в файл формата JSON. Это даёт возможность восстановить настроенные пресеты после «сброса на заводские настройки». Лично мне этой возможности очень сильно не хватало, т.к. при изменении внутреннего формата пресета приходилось то и дело переинициализировать всю EEPROM значениями по-умолчанию.
Добавлена возможность настраивать чувствительность датчика давления — т.е. задавать уровень давления, при котором система будет звучать «на полную громкость». И можно даже задавать некоторую нелинейность зависимости громкости от давления.
В прошивке центрального модуля сейчас 16000 строк (на C++), а в прошивке клавиатур — 2600 строк (на C++).
Публикацию проекта v3 в открытый доступ я не планирую, ибо практического смысла в этом не вижу.
Моё наблюдение за игрой Людовика показывает, что то, что он делает левой рукой, очень интересно. И очень мне непривычно; в музыкальной школе меня такому не учили даже близко, а самому узнать про такой подход к игре мне было просто неоткуда. Подобное басовое сопровождение он делает весьма часто. А значит приём достоин освоения.
Вот, осваиваю потихоньку. Промежуточный вариант — на этой записи:
В этот раз я использовал мой самодельный звуковой модуль с Кетроном, линейный выход на звуковую карту я в нём пока не сделал, поэтому пришлось записывать с колонки, с помощью микрофонов в телефоне.
Как это всегда бывает при попытках сыграть то, что руки ещё не запомнили, пока получается в лучшем случае «на троечку». Автоматизм в левой уже начал появляться, но до свободы в правой ещё далеко.
(А потом будет «следующий уровень» — в некоторых композициях Людовик сочетает подобную басовую линию с удерживанием аккордов. Такое — совершенно непохоже на традиционные «бас-аккорд», и поэтому очень интересно. Как говорится, «а что, так тоже можно было чтоли?»)
Рис. 1 КДПВ
P.S. пожалуй, стоит чуть пояснить смысл этой фразы:
в музыкальной школе меня такому не учили даже близко
Игра на выборке — это всё-таки несколько не то. Может быть, это особенность моего восприятия, но выборку я не воспринимаю как аккомпанемент. Звучание выборной левой и правой я не воспринимаю раздельно; это общее звучание со своим общим ритмом и фразами.