Привет, друзья!
Раз уж сказал "А", то рано или поздно придется ответить и за все другие буквы алфавита! Это я о том, что некоторое время назад, когда мои игры с ATtiny13 были в самом разгаре, я пообещал реализовать не только воспроизведение звука, при помощи этого микроконтроллера, но и запись. До воспроизведения руки дошли...
...а вот реализации записи помешали необоснованные цены на эти самые ATtiny13. Пролив пару скупых слез я со всем возможным энтузиазмом переключился на более интересные и менее дорогие китайские контроллеры семейства CH32V003, а точнее на контроллер младшей серии, в 8-выводном корпусе - CH32V003J4M6. Столько же ножек, сколько и у ATtiny! И коль скоро первые шаги в их изучении уже сделаны...
...пора приниматься за реализацию более серьезных задач. Тут-то я и вспомнил про данное обещание - создать устройство не только для воспроизведения, но и для записи звука.
Вообще, тема работы со звуком мне очень близка еще со времен учебы в аспирантуре. Свою диссертацию я писал на тему цифровой обработки речевых сигналов. Тогда таких универсальных микроконтроллеров в моем распоряжении не было, и я пользовался специализированными чипами от Analog Devices. Нынче времена уже не те! Похожими возможностями обладают даже микросхемы за 15 рублей! Тактовая частота - десятки Мегагерц, разрядность - 32 бита. Все это, как нельзя лучше, подходит для целей обработки звука. Грех не воспользоваться! Ну а кроме того для изучения возможностей этих самых CH32 нужна более-менее комплексная задача, позволяющая познакомится со всеми основными механизмами микроконтроллера. А звук записать, это вам не два байта переслать! Или, например светодиодами помигать!
Таким образом, сегодня мы с вами, дорогие читатели, будем создавать и программировать устройство, способное записывать звуковой сигнал с микрофона и воспроизводить его при помощи громкоговорителя.
Поехали...
Да, и не надо мне в комментариях писать о том что есть специализированные микросхемы! Да есть! Только нет в них того драйва, который мы сегодня испытаем!
Схемотехника устройства записи-воспроизведения звука
Коли у нас уже есть устройство воспроизведения (ссылка выше; там же есть вся необходимая теория), то казалось-бы, нет проще задачи чем подключить к нему микрофон, еще одну кнопку и доработать программу для поддержки записи. К сожалению, это верно лишь на первый взгляд. Основная проблема заключается в том, что микросхемы памяти, 24-й серии, которые я использовал для хранения звука имеют очень большое время записи.
Из справочника видно, что гарантированное время записи (twr) составляет 10 миллисекунд. Даже если писать память постранично (по 128 байт), а в ATtiny13 мы и этой возможности были лишены из за наличия всего 64 байт ОЗУ, то это не даст нам возможности приблизиться к приемлемой для нас частоте дискретизации звукового сигнала. Приемлемой я считаю частоту 16 кГц, которая дает полосу воспроизводимых частот около 7 кГц.
Здесь мне очень хотелось привести все доказательства с выкладками, но я сдержался! Кому будет интересно, пишите в комментариях - поделюсь.
В общем, медленно! Значит смотрим в сторону FLASH-памяти, скоростные характеристики которой гораздо лучше, но... Всегда есть это НО! Куда ж без этих назойливых проблем. Доступные микросхемы FLASH-памяти (а это 25-я серия) работают по последовательному интерфейсу SPI. А интерфейс SPI требует 4 линии передачи/приема информации. А в нашем целевом 8-пиновом чипе CH32V003J4M6 доступных ножек всего 6. А сколько нам нужно всего? Считаем:
- 4 ножки для SPI;
- 1 ножка для входа звукового сигнала;
- 1 ножка для вывода звука;
- 2 ножки для кнопок "запись" и "воспроизведение".
Итого 8 ножек. "В лоб" задача не решается! Будем немного "химичить". Значит так. Кнопки вешаем на 1 ногу через делитель напряжения, а опрашиваем уровень напряжения при помощи АЦП. Кроме того, используем вот какое допущение - кнопки не используются, когда происходит работа с чипом памяти. Тогда можно кнопки совместить с какой-либо сигнальной шиной управления памятью. Итого, все можно уложить в 6 ножек.
Главное, не забыть, что ножку 8 не стоит программировать на выход во избежание окирпичивания микроконтроллера.
Теперь, что у нас там по микросхемам памяти? Из недорогих (на Али около 60 рублей) мне удалось найти SST25VF010. У нее на борту аж целый мегабит памяти, что в 2 раза больше чем в предыдущем устройстве воспроизведения. Значит можно будет записать не 4 секунды звука, а около 8! Характеристики такие:
Нас интересует строка Tbp (внизу таблицы). Это время записи одного байта. Оно не превышает 20 микросекунд! Значит писать можно с частотой 50 кГц! Отлично! Более чем в 3 раза перекрывает наши потребности!
Так, за поисками компромиссов, анализом даташитов, бессонными ночами и рассуждениями о смысле жизни родилась принципиальная схема устройства.
Центром притяжения разработанного устройства является недорогой (кстати сейчас, во время распродажи на Али есть лоты менее 15 рублей за штуку с доставкой) китайский микроконтроллер CH32V003J4M6 на ядре RISC-V, который по своей структурной организации почти полностью повторяет известные STM32.
Звук будем подавать с микрофона, предварительно усилив его при помощи операционного усилителя. Схема абсолютно таже самая, что и в предыдущей статье про индикатор уровня звука (выше я давал ссылку). Схема отлично работает и не возбуждается даже при высоком коэффициенте усиления (в нашем случае около 1000). Кроме того она охватывает весь динамический диапазон от 0 до напряжения питания.
Это интересно! Микроконтроллер снабжен встроенным операционным усилителем, одно из назначений которого - усиливать сигнал для АЦП. В будущем я его обязательно "пощупаю". Однако для его задействования нам потребовались бы 3 ножки (на схеме: OPP, OPN, OPO), что я посчитал слишком жирным.
Воспроизводить звук я буду через простейший буферный каскад (усилитель мощности) на полевом транзисторе. В статье про воспроизведение звука на ATtiny (ссылка была выше), я проводил исследования различных вариантов подобных устройств и если не придираться, то вполне можно и так.
В конце статьи я, как обычно, дам ссылку на архив со всей необходимой для повторения или изучения устройства документацией. Там же будет ссылка на небольшой клип, демонстрирующий его работу. Можно будет оценить!
Звук, как я и упоминал, будем записывать и хранить во FLASH-памяти SST25VF010. Микросхема отличная! Очень быстрая. Мне необыкновенно понравилось с ней работать... в конце! А поначалу моя собственная самоуверенность буквально вогнала меня в тупик! Спешу предостеречь уважаемых читателей от двух проблем.
Во-первых, длина сигнальных проводов должна быть... короткой. Я сперва для эксперимента собрал все на бутерброде. Как-то так:
В середине FLASH-память на панельке, установленная в бредбоард. С микроконтроллером соединяется шлейфом. Так вот, при таком подключении на шине данных как при чтении, так и при записи возникают помехи. Я сначала не понял, но когда потом сравнил сигналы с аналогичными сигналами программатора CH341, все встало на свои места.
Пользуясь случаем. Замечательное устройство анализатор логических сигналов является незаменимым помощником при отладке цифровых устройств. Например такой, из серии недорогих (рублей 300 стоит).
Во-вторых, несмотря на то, что ножки FLASH-памяти, предназначенные для защиты от записи (WP#) и останова (HOLD#) я не задействовал это не причина их ни к чему не подключать. Обязательно следует соединить их с шиной питания (активный сигнал на них - низкий). В противном случае чип вообще может показаться "мертвым".
Две кнопки "Запись" и "Воспроизведение" я подключил через делитель напряжения с изменяемым коэффициентом деления. Если обе кнопки отжаты, то на аналоговый вход микроконтроллера подается напряжение питания, через резистор R10. Если нажата кнопка "Запись", напряжение подается через делитель, образованный резисторами R10, R11. Это примерно 91% напряжения питания. Если нажата кнопка "Воспроизведение", то делитель образуется парой сопротивлений R10, R9 и на вход подается примерно 82% напряжения питания. Как видно, уровни напряжения находятся, в любом случае, у верхней границы питания. Это сделано умышленно. Дело в том, что к этому же пину подключен сигнал активации микросхемы FLASH-памяти. Так вот, чтобы нажатие на кнопки не приводило к появлению низкого уровня, активизирующего чип памяти, уровни выбраны достаточно большими, но все же различимыми для АЦП нашего микроконтроллера.
И, наконец, последний узел схемы - стабилизатор питания на 3 Вольта. Нужен он вот зачем. Диапазон напряжений питания микроконтроллера и памяти отличается. Микроконтроллер готов скушать от 2,5 до 5,5 Вольт. Это здорово! Но, к сожалению, того же нельзя сказать про FLASH-память, диапазон напряжения питания которой 2,7...3,6 Вольта. Запитать устройство от батареи CR2032 можно, если не включать воспроизведение звука. Подключение динамика сразу "просаживает" такую батарейку. Значит, надо питать либо от двух пальчиковых, что довольно громоздко, либо от литиевого аккумулятора. А он заряжается до 4,2 Вольта. Микроконтроллер выдержит, а вот чип памяти явно прикажет долго жить... Значит, возникает потребность в понижении напряжения питания. Вот эту функцию и выполняет линейный преобразователь XC6206P302MR. Можно использовать и другие, с подходящим напряжением. У меня просто есть такие. Купил на Али штук 20! Ток у них небольшой, поэтому сам динамик я подключил непосредственно к входному напряжению, чтобы большой ток не спалил стабилизатор.
Справа вверху расположен разъем программирования микроконтроллера. На вывод 8, через который программируется CH32 я повесил функцию входа звуковых данных, чтобы не программировать этот вывод как выход. Помним - это сразу "окирпичивание!
Выходы таймера CH32, через который мы будем выводить звуковой ШИМ-сигнал есть на любом выводе микроконтроллера, так что оставшиеся выводы я раскидал так, чтобы удобно было разводить печатную плату.
Печатная плата
Печатную плату я как обычно разводил в редакторе EasyEDA, но доводил ее уже в Sprint-Layout. В нем мне удобнее готовить макет для фрезерного станка, на котором я вырезаю все печатные платы.
Печатная плата также будет в архиве в конце статьи.
Развести однослойную печатку без перемычек мне, к сожалению, не удалось. Но, поскольку 2-слойные я не люблю, да и другим не желаю, то предусмотрел место для специальных контактных площадок, чтобы подпаять перемычки. На скриншоте их хорошо видно.
Естественно, что в изначальном варианте не обошлось без казусов. Передвигая элементы в Sprint-Layout я удалил (мешались сильно) и потом забыл развести две неиспользуемые ножки чипа памяти на питание. На скриншоте и в в архиве вариант с уже внесенными исправлениями.
Вырезанная плата выглядит так.
Большой полигон в левом нижнем углу никакого сакрального смысла не имеет. Расположен он под микрофоном и сделан чтобы сократить время фрезерования.
Микрофон, кстати в корпусе DIP и расположен со стороны SMD-компонентов. Паять не очень удобно, поэтому в таких случаях я использую мелкие монтажные пистоны, которые устанавливаю в отверстия.
Не часто их использую, поэтому забыл, что лучше их устанавливать с другой стороны. Тогда разорвавшиеся края можно аккуратно припаять к дорожкам.
Запаиваю я все так. Сначала чипы и полупроводники. Они самые "тесные", обычно. Лучше их паять пока другие компоненты не мешаются.
Потом достаю коробку с резисторами и паяю все резисторы.
Тут я тоже отвлекся и вместо 47-килоомного впаял 100-килоомный. Потом кнопки выдавали одинаковый сигнал. Но с этим быстро разобрался.
Потом достаю коробку с конденсаторами и запаиваю их, а потом и все остальное.
Поскольку забыл развести пару выводов FLASH-памяти, то получилось на 2 перемычки больше! А еще, вместо резистора 47 килоом я установил 4,7! Так тоже работает, только уровни детектирования АЦП надо поменять и не нажимать на кнопки во время воспроизведения!
Красной меткой помечен плюсовой вывод аккумулятора. С обратной стороны нанесена маркировка. Между микрофоном и платой установлена прокладка, чтобы микрофон не замыкал печатные дорожки.
В общем, было весело! Приступаю к программированию.
Разработка управляющей программы микроконтроллера
Управляющую программу я писал в VS-Code с использованием PlatformIO и отличными темплейтами wagiminato-ра. Правда использовать я стараюсь только системные библиотеки, чтобы лучше познакомится с регистрами CH32.
Общая логика программы следующая. Таймер - основной элемент управления. С его помощью задается тактовая частота оцифровки и воспроизведения звука. По таймеру производится как запуск АЦП при записи, так и модификация аппаратного ШИМ-сигнала, который снимается с вывода того же таймера.
Частота, с которой должен осуществлять счет таймер вычисляется так:
Ftim = Fsound * 256
Здесь Fsound - частота дискретизации звука, а 256 - разрешение сигнала ШИМ. Если предположить, что частота дискретизации равна 16 кГц (к чему я стремился), то частота запуска таймера получается 4,096 МГц. Для получения такой частоты нужно установить предделитель таймера в значение
Kpred = Fcpu / Ftim
Если тактовая частота максимальна и равно 48 МГц, то коэффициент равен примерно 11,72. Ближайшее значение предделителя - 11 или 12. При этом получаем тактовую частоту или 17045 или 15625 Гц. В программе можно выбрать любой предделитель и поэкспериментировать с качеством звука, а значит и с длинной звукового фрагмента, который размещается в памяти.
Каждый отсчет звука мы будем сохранять в виде одного байта информации. Это 256 уровней. Значит, таймер нужно перезагружать каждые 256 тиков. За это отвечает регистр перезагрузки. После переполнения этого регистра будет вызываться прерывание в котором мы будем выполнять основную работу.
При записи звука в прерывании будет запускаться АЦП, а полученный отсчет будет записываться во FLASH-память. Можно запускать АЦП и без прерывания, синхронизировав таймер и АЦП напрямую. Такая возможность есть у микроконтроллера, но для однообразия алгоритма я ей не воспользовался.
При воспроизведении же звука по прерыванию программа считывает очередной отсчет из FLASH-памяти и модифицирует 4-й регистр сравнения таймера. Четвертый потому, что он связан с выводом, на который я повесил усилитель мощности (вывод 7, пин PC4, альтернативная функция T1CH4).
Это интересно! У микроконтроллеров семейства CH32 есть возможность управления полумостовыми или мостовыми парами транзисторов. Это позволяет их использовать как ШИМ-регуляторы в источниках питания, в качестве драйверов электродвигателей или для раскачки выходных каскадов усилителей мощности класса D без иных защитных механизмов, напрямую подключая выводы.
Взаимодействие с FLASH-памятью в нашем устройстве происходит при помощи программной эмуляции протокола, поскольку аппаратные SPI выводы в 8-пиновом корпусе отсутствуют. Но никаких проблем с этим не возникло!
Немного меня смутил блок атрибутов в определении функции прерывания. Он выглядит так:
__attribute__((interrupt("WCH-Interrupt-fast")))
Я попробовал разобраться зачем это нужно и вот что выяснил.
Микроконтроллер аппаратно сохраняет регистры при вызове прерывания, поэтому из функции можно удалить пролог и эпилог. Это делает ее компактнее. В этом и заключается назначение атрибута.
На этом, пожалуй, все основные особенности программы закончились. В скомпилированном виде она заняла 1468 байт или 9% от всей памяти программ микроконтроллера.
Это очень неплохо, учитывая 32-битную структуру команд-данных CH32. для сравнения с ATtiny можно поделить эту цифру на 2. То есть для ATtiny код занял бы 700...800 байт. Это около 75 процентов всей памяти! Вы согласны за это платить в 6 раз больше? Я тоже нет. Поэтому сейчас, пока идет распродажа я заказал лот из 20 штук за 300 рублей CH32V003J4M6. Надеюсь, что счастья мне хватит надолго!
А с устройством я еще планирую поразвлекаться. Идей много! А что если изменить скорость воспроизведения? А добавить реверберацию или эхо? А сделать кукольный голос? Все это можно с той мощью, которая скрыта в недрах этого маленького контроллера!
Архив с документацией по проекту доступен для скачивания:
Короткий клип с иллюстрацией работы устройства можно посмотреть здесь:
Спасибо, что читаете-смотрите Terrabyte! Подписывайтесь, если вам интересна радиолюбительская тематика, микроконтроллеры, мини-ПК, необычные компьютерные решения и инновационные разработки! Спасибо всем, кто поддерживает нас с братом своими комментариями и лайками!
Наша группа ВК: https://vk.com/terrabyte
Наш канал на VK-Video: https://vk.com/video/@terrabyte/all
Наши разработки: