Вот в догонку "музыка" для теста экрана УКНЦ ты же воде спрашивал:
https://yadi.sk/d/jX-MxBw87ez5JA
Вид для печати
Вот в догонку "музыка" для теста экрана УКНЦ ты же воде спрашивал:
https://yadi.sk/d/jX-MxBw87ez5JA
Manwe, если выбросить синхроимпульс, да и вообще кодировать читаемый бит половиной волны, то есть изменений уровня будет в два раза меньше, не получится ли увеличить скорость до 10Кбит? К примеру каждые 4 бита можно кодировать по такой табличке:
00110011 00100101 00101001 00101011
00101101 00110101 01001001 01001011
01001101 01010011 01011001 01011011
01100101 01101001 01101011 01101101
Единственное неудобство в том, что первое значение имеет только 4 перехода, а не 6. Но если длинную полуволну понимать как 0, то прочитав 4 бита и получив нуль, нужно сразу переходить к трансляции значения и добавлению очередных 4х бит, иначе нужно прочитать еще 2 бита и потом уже делать трансляцию. При таком кодировании соотношение нулей и единиц получается либо равным, либо 3 к 5, что вроде не должно привести к сильному уплыванию уровня. Кроме этого время передачи 4х бит и скорость загрузки всегда будут одинаковыми.
Я сейчас работаю над этим. Первой задачей было выжать максимальную скорость из стандартного загрузчика ПЗУ. А теперь уже можно писать свой загрузчик. Пока что проблема в определении производительности: замеряю подпрограмму, она длится 80 тактов – вроде бы всё логично, по командам так и должно получаться. Заставляю эту же программу читать WAV (с частотой дискретизации вычисленной по формуле N*80) – съезжает синхронизация. Подгоняю частоту WAVа и оказывается что подпрограмма выполняется 82 такта. Как такое может быть – непонятно. Продолжаю исследования.
Update: Удалось добиться скорости 6066 бод - это в два с лишним раза быстрее, чем здесь: https://www.instagram.com/p/BwAfRFXjKJK/
Я пока не сверяю контрольную сумму, но на вид картинка грузится без ошибок. Проблема в том, что частоту дискретизации WAV я подобрал экспериментально (чтобы периоды настроечного тона считывались целое число раз), но эта частота никак не укладывается в целое число тактов процессора (84.6 тактов?!). Формулы нет. Всё наугад. Это чревато тем, что другая БК0010 может и не прочитать WAV с такой частой. Нужны добровольцы с БК0010 для тестов.
Можно развернуть цикл BIT/BEQ и выбросить счётчик, подстройку нужно будет делать выбирая на какую пару команд перейти, если один из переходов сработает значит импульс короткий, если нет, значит длинный и нужно дождаться его окончание. Общую настройку делаем просто перебирая число команд в развёрнутом цикле и определяя в каком диапазоне читаются только короткие импульсы, а потом будем использовать среднее значение.
У меня другая кодировка: не шириной импульсов, а скважностью. Это удобно тем, что посчитав длину высокого и низкого уровня, я просто сравниваю эти два числа и сразу получаю бит C, который тут же выдвигаю в выходной поток данных.
Развернуть циклы я думал, но это не поможет точно рассчитать частоту – всё равно не сходится с теоретической. В теории с INC цикл длится 56 тактов, а без него 44. Ускорение на 27% (7720 бод) может привести к поднятию частоты на такую, с которой уже не справится источник звука. Но я всё равно попробую что-то такое.
Спасибо за тему!
У меня есть некоторое количество БК, есть кассеты с играми тех годов. Заказал новый магнитофон teac, т.к моя Вега-122 постоянно барахлит. Я так понимаю для БК0010-01 мне загрузчик и не понадобиться? Буду изучать.
- - - Добавлено - - -
В дополнении хочу сказать. Что в той деке teac которую я заказал есть usb подключение к PC можно сразу оцифровать кассеты которые у меня есть. Может там что есть редкое.
Совершенно верно. Просто в конверторе не менять настройки, выбрать файл .bin и нажать кнопку «Сконвертировать». Скачается WAV.
Я воспроизводил WAVы с iPhone и с плеера Sansa Clip, оба на максимальной громкости. БК0010-01 читает без единой ошибки. Если же источник звука некачественный и ошибки случаются, надо снять галочку «Дополнительное ускорение на 11%».
У меня код чтения получается примерно такой:
В теории, после настройки он может ловить импульсы минимальной длительностью от SET1 до RTS плюс время нескольких пар BIT/BEQ чтобы можно было различать длинные и короткие импульсы. Правда нужно выравнивать длины веток переходы на которые помечены как add NOPS. Настройка заключается в установке LINEH/LINEL на последнюю пару BIT/BEQ(BNE), и попытке приёма одного слова. Затем передвигаем их назад, пока мы не определим весь диапазон устойчивого приёма слов настроечного сигнала, после чего метки нужно поставить посередине. По сравнению с кодированием скважностью, когда 1 бит кодируется двумя полуволнами, здесь для кодирования 4х бит требуется 6 полуволн(и 4 для кодирования комбинации 0000), то есть для скорости 10 кбод, частота будет чуть менее 7500 Гц.Код:MOV AAA,Rbuf ; начало буфера
MOV NNN,Rlen ; длина буфера
WAITZ: BIT / BNE WAITZ ; вход должен находиться в пассивном состоянии
JSR BUFRD ; вызываем функцию чтения
BUFRD: MOV 1,Rdata ; регистр для накопления слова c флагом для 16 бит
MOVB 4,Ridx ; регистр для накопления индекса с флагом для 6 бит
WAITH: BIT / BEQ WAITH ; ждём первый бит
BR LINEH ; переходим к измерению длительности
;дальнейший код нужен еще в одном экземпляре для другой полуволны
BIT / BEQ SET1 ; если переход сработает значит импульс короткий
LINEH: BIT / BEQ SET1 ; положение данной метки настраивается в записимости от скорости
BIT / BEQ SET1
WAITL: BIT / BNE WAITL ; переходы не сработали, значит импульс длинный, ждем окончание
;длинный импульс
SET0: ASLB Ridx
BCS SET2 ; add NOPS флаг индекса вылез, значит получено 6 бит
CMPB 64,Ridx
BEQ SET2 ; флаг не вылез, но это нуль из 4х бит
ASL Rdata ; сдвигаем данные по каждому длинному импульсу
BCS SAVE1 ; флаг вылез значит это последняя тетрада слова
BR LINEL ; add NOPS
;короткий импульс
SET1: ASLB Ridx
BCC INC1 ; флаг индекса не вылез, значит нужно только добавить 1 и читать следующую полуволну
INC Ridx ; флаг индекса вылез, длинных испульсов было только 2
ASL Rdata ; значит нужно сдвинуть данные еще 2 раза
SET2: ASL Rdata
BCC SUM1 ; флаг еще не вылез, значит это не последняя тетрада
SAVE1: ADD (Table+Ridx),Rdata ; конвертируем индекс по таблице, нуль имеет индекс 64
MOV Rdata,(Rbuf)++ ; сохраняем данные
MOVB 4,Ridx ; ставим флаг индекса
MOV 1,Rdata ; ставим флаг данных
SUB 1,Rlen ; уменьшаем длину
BNE LINEL ; читаем другую полуволну
RTS
INC1: INC Ridx
BR LINEL ; add NOPS
SUM1: ADD (TableOdd+Ridx),Rdata
MOVB 4,Ridx
BR LINEL ; add NOPS
Идея с шестью полуволнами хорошая, но я опасаюсь, что что-то может пойти не так во время сохранения прочитанных четырёх бит. Не факт, что удастся подогнать длительность операции сохранения под нужное число тактов (как я писал выше, теоритический расчёт не соответствует практическим данным), и тогда собьётся синхронизация.
У меня уже возникала проблема на границе байта – из-за операций перехода на следующий байт неуверенно читался следующий бит (длинная единица иногда считывалась как короткий ноль). Эту проблему я поборол добавлением 2 к счётчику, но это приблизительное решение (не точно соответствует числу тактов). На другой частоте дискритизации может не сработать.
Для выравнивания веток лучше всего использовать не NOP, а такие же команды как используются в длинной ветке, а ненужные результаты записывать в Rtemp. Ну а команду сохранения меняем на команду загрузки, только указатель не увеличиваем. Данному коду требуется, чтобы длина короткой полуволны была больше, чем время выполнения от SET1 до RTS, а вместе с пачкой BIT/BEQ была перекрыта и длинная полуволна(иначе будет непонятно где середина устойчивого приёма). Можно для начала сделать и со счётчиком, правда там придётся делать его загрузку, проверку и условный переход, что несколько снизит максимальную скорость приёма. Вообще для выравнивания времени выполнения кода можно сделать следующее:
1) подать на вход сигнал с некоторой частотой(с ним будем сравнивать время выполнения кода)
2) дождаться начала положительного импульса(это нужно будет делать для каждого измерения)
3) выполнить эталонную ветку заменив условные переходы на безусловные
4) скопировать 256 раз состояние входа в память, после чего вывести полученную зебру на экран
5) дождаться нового импульса и выполнить другой код
6) прочитать 256 раз состояние входа и вывести рядом с первым
7) по сдвигу между выведенными полосками мы сможем определить насколько совпадает время их выполнения
8) добавляем или убираем команды и повторяем эксперимент
PS: можно вообще дождаться импульс, после чего 256 раз прогонять код и записывать по 1 значению входа, тогда вид зебр станет одинаковым при идеальной подгонке кода, иначе чем ближе к концу, тем больше будет расползаться.
PPS: Пришла тут мысль, что лучше использовать кодирование 3 длинных/3 коротких, там всего 20 комбинаций, но если выкинуть 011011011, 001001001 и еще парочку, то соотношение 0 и 1 во всех случаях будет 4/5, и код несколько упрощается:
Если нам не требуется фиксированная скорость, и вход позволяет принимать данные при соотношении H и L равном 1 к 2 или наоборот, можно всё существенно упростить, причём ветка с сохранением получается достаточно короткой:Код:LDDAT: MOV 1,Rdata ; флаг для отлова окончания слова
LDIDX: MOVB -4,Ridx ; 6 флагов для отлова окончания индекса
WAIT0: MOV Tune,Rcnt
INC0: DEC Rcnt
BIT
BNE INC0
ASL Rdata ; всего здесь слово будет сдвинуто 3 раза
ASLB Ridx ; индекс двигаем 2 раза чтобы не двигать в длинной ветке
ASLB Ridx
ASL Rcnt ; добавляем едриницу в предпоследний бит
ADCB Ridx
ASL Rcnt
ADCB Ridx ; add NOPS
WAIT1: MOV Tune,Rcnt
INC1: DEC Rcnt
BIT
BEQ INC1
ASL Rcnt ; устанавливаем младший бит индекса
ADC Ridx
BMI WAIT0 ; add NOPS если индекс еще не закончился
ASL Rdata ; 4й раз сдвигаем данные и проверяем не закончилось ли слово
BCC BADD
ADD (Table+Ridx),Rdata ; сохраняем если закончилось
MOV Rdata,(Rbuf)++
DEC Rlen
BNE LDDAT
RTS
BADD: ADD (Table+Ridx),Rdata
BR LDIDX ; add NOPS
Код:MOV 1,Rdata
MOV Tune,Rcnt
WAIT0: DEC Rcnt ; ждём первый и нечётные биты
BIT
BNE WAIT0
ASL Rdata
ASL Rcnt
MOV Tune,Rcnt
ADC Rdata
ASL Rdata ; сдвигаем здесь, чтобы не двигать когда придёт последний бит
BCC WAIT2 ; add NOPS
WAIT1: DEC Rcnt ; ждём последний бит
BIT
BEQ WAIT1
ASL Rcnt
MOV Tune,Rcnt
ADC Rdata
MOV Rdata,(Rbuf)++
MOV 1,Rdata
DEC Rlen
BNE WAIT0
RTS
WAIT2: DEC Rcnt ; ждём чётные биты, кроме последнего
BIT
BEQ WAIT2
ASL Rcnt
MOV Tune,Rcnt
ADC Rdata
BR WAIT0 ; add NOPS