Spin FV-1 Tutorial

Материал из GTwiki
Перейти к: навигация, поиск

Общее

Spin FV-1 - микросхема "все в одном" для выполнения алгоритмических операций над звуком в цифровом виде.
Содержит 24 бит стерео АЦП, 24 бит стерео ЦАП, DSP ядро, вход на три потенциометра для изменения параметров, индикатор клиппинга.

ТТХ простым языком

Частота дискретизации как правило задается часовым кварцем , либо внешним генератором и составляет обычно 32768 сэмплов в секунду. Максимальная стабильная частота дискретизации от внешнего источника тактов - 48000 сэмплов в секунду (пруф). Для справки, дискретизация компакт-диска 44100@16бит, процессора Zoom 505 - 708 - 31250@16бит.

Размер ОЗУ - 32768 слов, но уже не 24 бит, а 14 бит с упаковкой (алгоритм в даташите не описан).
Разрядность АЦП потенциометров - 9 целых 1/512 бит (513 значений, от 0 до 512).
Внутри DSP ядра 32 регистра общего назначения по 24 бит.
Аккумулятор 24 бит.
Операнды разного формата, зависит от команды и к чему обращаемся, ОЗУ, или РОН, как правило, знаковые дробные с фиксированной точкой.

Из аппаратных средств можно отметить два генератора низкой частоты (LFO) синусоидальной формы (sin 0,1) и два генератора пилообразной формы (ramp 0,1).
Забегая вперед, отмечу, что генерация треугольной формы выполняется "зеркалированием" пилообразной. Разрядность, а следовательно, и точность LFO различается в разы. У пилы 16 бит частота, но только 4 значения амплитуды. У синуса частота только 9 бит, но точность амплитуды - 15 бит (пруф).

Пример исходной программы со знаковыми дробными с фиксированной точкой:

rdax   pot0 , 0.3      ;get pot0 (to 0.3 of memory range) 
rdfx   reg5 , 0.001    ;filter delay control 

Декомпилированный пример программы, (т.е. как реально выглядят заданные числа в памяти чипа) :

        RDAX        POT0 , 0.29998779296875                     ; 0.29998779296875*[POT0] + ACC
        RDFX        REG5 , 0.0009765625                         ; (ACC-[REG5])*0.0009765625 + [REG5]


Параметры i2c

У чипа прошито 8 заводских программ, так же он может считывать еще до 8 программ с EEPROM микросхемы типа 24LC32A по шине i2c.

Частота i2c шины - около 260кГц, напрашивается вывод, что 2^15 степени Герц тактовой частоты кварца умножаются на 8. Соответственно, при 50кГц тактовой, частота i2c должна быть в районе 400кГц. Судя по даташиту на 24LC32 , чип может не потянуть 400кГц тактовой при питании от 3.3 вольт.

Подтягивающие резисторы уже стоят внутри чипа, номинал 4К-5К, в зависимости от тех. процесса.
На своей девборде я поставил внешние резисторы по 10К, т.к. иногда МК (STM32F0) и ПЗУ общаются когда FV-1 вынут из схемы.
Когда FV-1 вставлен, получается, что внешние 10К стоят в параллель внутренним 4К..5К, но все работает ОК, хотя подключенный щуп осциллографа к линии данных сводит работу на нет и приводит к ошибкам обмена данными.
Так же, бывали ситуации, когда без выпайки внешней подтяжки чтение с внешнего ПЗУ не работало.

Spin FV-1 vs Alesis/Wavefront AL3201B

Иногда вижу флэйм на этот счет. Не о чем флэймить, это родственники. Великие вещи не берутся из ниоткуда. Keith Barr основал MXR в 1974м, потом MXR был продан Джиму Данлопу, и в 1984м Кейт основал Alesis. В 2003 продал и её, и был, как минимум, участником Spin Semiconductor и разработчиком Spin FV-1.
Как я понимаю, финансовое положение и здоровье не позволяли добиться большего. А при раскрутке Spin FV-1 использовать заикание про Алесис и MXR было нельзя, мигом впаяют неправомерное использование чужой торговой марки.
Поэтому, у девайсов схожая архитектура. Но:
у Spin FV-1 один чип на все. Три потенциометра для рулежки. i2c интерфейс для подкачки пользовательских программ. Доступный кварц маленького размера.
У AL3201 - набор из трех микросхем. Подобие SPI интерфейса, но нет аппаратной поддержки конкретной микросхемы ПЗУ. Нет поддержки потенциометров, но можно на ходу изменять данные в программе без перезаписывания программы целиком.

Получается, Spin FV-1 + 24LC32A достаточно мощный и самодостаточный кастом комплект, когда для AL3201 надо еще микроконтроллер для опроса потенциометров и хранения программ.
И оба чипа вышли слишком рано для своего времени...

Как оно работает, простым языком

Упрощенно, работа чипа похожа на синхронный конечный автомат.
Каждый такт (а их 32768 в секунду при использовании часового кварца) защелкиваются данные с АЦП (входы аудио и потенциометров) и запускается программа длинною 128 команд.


Каждая команда длиной 32 бита, длина всей программы постоянна и составляет 512 байт.

Система команд элементарна:

  • Среди команд могут быть операторы работы с памятью, регистрами, а так же "ввода-вывода", т.е. чтения входных АЦП аудио и АЦП потенциометров, запись аналогично - регистры, память, ЦАП аудио. Так же, есть команды управления LFO.
  • Есть команда относительного условного перехода, переход возможен только вперед, до 64 команд.
  • Если команд в программе менее 128, то неиспользованная область добивается компилятором nop'ами (по факту, безусловный переход на следующую строку).
  • В 128 команд надо уложить все, левый, правый канал и т.п. Известны случаи мультиэффектового использования Spin FV-1 , когда на левом канале крутился алгоритм, допустим, хоруса, а на правом - ревер, или фэйзер. И выход левого канала замыкался проводом на вход правого. Но можно "замыкать" и в программе, все равно, 3 общих потенциометра и общая память.
  • Потенциометры читаются как линейные. Для имитации логарифмической характеристики данные считанные с потенциометра возводятся в квадрат, либо в куб, с соответствующей потерей точности.
  • Операторов циклов - нет.


Архитектура унаследована от самых первых ревербераторов сконструированных Кейтом Барром, когда на адресной шине процессора (вероятно, Z80) старшие биты были адресами ОЗУ, а младшие - ПЗУ. И между циклами регенерации динамического ОЗУ как раз укладывалось 128 команд ПЗУ. Таким образом, на цикл чтения ОЗУ приходилось 128 циклов ПЗУ.

Со временем, оборудование ценой $100 эволюционировало в один чип - Spin FV-1, ценой менее $17.

ОЗУ

ОЗУ емкостью 32768 слов по 14 бит (упакованных, но алгоритм не озвучен) работает как разомкнутое кольцо. Т.е. каждый новый тик кварца физический адрес увеличивается на 1 и данные сдвигаются вверх по адресному пространству.
Если записать в текущем адресе, допустим, 1, в нулевой адрес, то при следующем цикле эта единица будет уже по адресу 1, поэтому задача завести данные в память в обратном порядке похожа на квест.

Если качество звука не впечатлит, есть рецепт как сделать разрядность памяти из 14 бит 24, при этом потери памяти в 2 раза, т.к. отдельно хранятся старшие 14 бит, отдельно остатки.

Написание программ

Работа ведется на языке Spin Asm в среде производителя. Ассемблер простой, всего 20 команд.
Средств отладки - нет. Теоретически, поморгать светодиодиком для отладки можно, если повесить его через повторитель или резистор 10кОм на выход одного из ЦАП (как правило, правый канал), делая систему моно.
Откомпилированный пакет программ (1-8) зашивается в микросхему EEPROM памяти с интерфейсом i2c.
Spin FV-1 считывает программу при соответствующей комбинации бит выбора номера программы.

Алгоритм простого дилея в 1 секунду

Чтение АЦП левого канала.
Запись в ОЗУ по адресу 0.
Чтение ОЗУ по адресу 32767.
Запись в ЦАП левого канала.
Все. Остальное все комплятор добьет nop'ами.


; Пример самой простой задержки на 1 секунду, только один повтор, без зацикливания и обратной связи.
; На выходе только задержанный сигнал. Чистый должен быть подмешан аппаратно, например, блендером.

	LDAX 	ADCL		; чтение АЦП в акк. Предыдущее значение акк. игнорируется
	WRA 	0 , 0 		; Запись ОЗУ, адрес 0 , коэфф.=0 :: Пишем АЦП в нулевое слово, и чистим акк.
	RDA	32767,1		; читаем последнее слово ОЗУ 
	WRAX	DACL,0		; и пишем в ЦАП, чистим акк.
				; конец программы

Соответственно, чтобы дилей был в 0.5 секунды, данные надо читать по адресу не 32767, а 16383. А для 0.25 секунды - 8191.

Для времени задержки определяемой потенциометром, можно адрес умножать на значение потенциометра [0..1] и тут мы влетаем на такую вещь, как разрядность АЦП потенциометров, которая составляет 9 бит. А разрядность адреса памяти - 6 бит.


Получается, регулировка задержки кратна 2^15/2^9=2^6=64 слова , если использовать все пространство под задержку, что не так уж и много, по современным меркам.

; Пример самой простой задержки на 1 секунду, с зацикливанием.
; На выходе только задержанный сигнал. Чистый должен быть подмешан аппаратно, например, блендером.
; Читаем АЦП, пишем половину в регистр.
; Берем последний байт ОЗУ, воспроизводим, половину суммируем с регистром, пишем в нулевой байт ОЗУ.

	CLR			; чистим акк.
	RDAX   	ADCL,   0.5    	; чтение АЦП и уменьшение в 2 раза, чтобы не зашкалил уровень после микса с повторами
	WRAX 	REG0,	0	; запоминаем в регистре ACC->REG, чистим акк.

	RDA	32767,	1	; читаем последнее слово ОЗУ (т.е. на секунду позже)
	WRAX	DACL,	0.5	; пишем в ЦАП, умножаем на фидбэк

; теперь смешиваем половину задержанного сигнала с половиной нового сигнала полученного выше и сохраненного в REG0
	RDAX	REG0,	1	; 1*REG0+ACC = сумма половины АЦП и половины последнего слова ОЗУ
	WRA 	0 , 0 		; Запись ОЗУ, адрес 0 , коэфф.=0 :: Пишем АЦП в нулевое слово, и чистим акк.
eof:				; Конец программы

Сделать вывод сигнала с подмесом чистого - дело перестановки пары строк. Достаточно выводить в ЦАП звук не последней ячейки, а первой, к которой подмешаны повторы.


А если вместо коэффициентов 0.5 поставить POT0 и POT1, то будут хоть и упрощенно, но регулироваться громкость чистого сигнала и фидбэк.



Хорус для самых начинающих

; sine chorus v04
; final очередной
; примитивный хорус по синусу. 
; клина на выходе почти нет.
; потенциометр2 -  фидбэк. (0..1)
; потенциометр1 - частота LFO (0..1   , по сути, те же 9 бит, что тянет LFO)
; потенциометр0 - глубина.  Размах LFO, на сколько отклоняться от центра. Без ограничителей, поэтому  запросто залезет за пределы буфера в 2000.

	mem 	chordel	2000			; память хоруса. По факту вся память будет под хорус

	EQU	temp	reg16	
	EQU	filter	reg17	

	skp	RUN,	LOOP
	wlds	1,	127,	1500		; первичная настройка LFO. Можно и не делать, ибо потенциометры все равно все испраят. SIN1 , FREQ 9 bit, amp 15 bit
LOOP:
	CLR

;рулежка
	rdax	POT1 ,		1.0		; читаем первый потенциометр
	mulx 	POT1				; возводим в квадрат, закос под логарифм
	wrax	SIN1_RATE ,	0		; пишем его значение в частоту LFO1

	rdax	POT0 ,		1.0		; читаем нулевой пот
	mulx 	POT0				; возводим в квадрат, закос под логарифм
	wrax	SIN1_RANGE ,	0		; пишем его значение в размах LFO1 

; сам хорус
; чтение памяти по позиции LFO и интерполяция с соседней ячейкой.
	cho	RDA ,		SIN1,0x06,	chordel+1000	;sweep about midpoint
	cho	RDA ,		SIN1,0,	chordel+1001	;interpolate between ajacent samples

	wrax	DACL	,	1.0		;write to left out, clear acc

	MULX   POT2 				; к тому, что выводим, подмешиваем чистый
	RDAX   ADCL ,	-1  

	wra	chordel ,		1		; зацикливание повторов
eof:				; Конец программы

Видно, что строк всего ничего. LFO можно не инициализировать, потенциометры не логарифмить. Значения потенциометров не ограничиваются, если хоть немного крутнуть POT0 , то границы хоруса выйдут вне заданного буфера и задержка прилично увеличится, но работать все будет.

Для начала - этой программы хватит, дальше можно дописать ограничители, фильтры и прочее. И, кстати, фазы чистого и задержанного сигнала играют не последнюю роль. Ибо хорус может немного подыгрывать как тремоло.