Просмотр полной версии : Безвейтовый контроллер PS/2 клавиатуры на AVR без CPLD для ZX Spectrum и клонов
oistalker
21.11.2020, 19:54
По примеру соседней темы (https://zx-pk.ru/threads/30305-bezvejtovyj-kontroller-ps-2-klaviatury-na-avr-cpld-dlya-zx-spectrum-i-klonov.html), представляется ко вниманию. Вдруг, кому пригодится, если не будет CPLD на 5V IO под руками. Вместо CPLD используются 8 сдвиговых регистров 74HC595, в остальном принцип работы идентичен варианту контроллера с CPLD (даже прошивка подошла с минимальными изменениями). Может быть, конечно, тут уже была такая реализация, но я не нашёл.
Схема: 73998
Собрал это дело на макетной плате
http://i.imgur.com/rd7BPYOm.jpg (https://imgur.com/rd7BPYO)
И заказал на jlcpcb печатную плату,
http://i.imgur.com/dVanD8Tm.jpg (https://imgur.com/dVanD8T)
если никаких ошибок в разводке нет и оно заработает, - дополню пост материалами с гербер файлами и модифицированной прошивкой AVR. Спасибо за внимание :v2_dizzy_gamer:
обновление сообщения:
Cхема для Rev3: 74934
Файлы для изготовления платы Rev3: 74935
Прошивка c исходниками (фьюзы нужно лить такие High=0xDA Low=0xFF Ext=0x05) : 74936
заметки о плате Rev3 в сообщении (https://zx-pk.ru/threads/32473-bezvejtovyj-kontroller-ps-2-klaviatury-na-avr-bez-cpld-dlya-zx-spectrum-i-klonov.html?p=1108412&viewfull=1#post1108412)
Идея интересная, я бы только сигналы D0-D4 переименовал в KL0-KL4 или типа того.
andykarpov
22.11.2020, 00:32
Прикольно! А как работает джойстик?
Serg6845
22.11.2020, 10:05
По примеру соседней темы (https://zx-pk.ru/threads/30305-bezvejtovyj-kontroller-ps-2-klaviatury-na-avr-cpld-dlya-zx-spectrum-i-klonov.html), представляется ко вниманию. Вдруг, кому пригодится, если не будет CPLD на 5V IO под руками. Вместо CPLD используются 8 сдвиговых регистров 74HC595, в остальном принцип работы идентичен варианту контроллера с CPLD (даже прошивка подошла с минимальными изменениями). Может быть, конечно, тут уже была такая реализация, но я не нашёл.
Схема: 73998
есть один момент - в случае когда для опроса клавиш одновременно падают в 0 больше одного адреса - в такой схеме возникнет конфликт выходных уровней у активных регистров. чтобы этого избежать - нужно либо регисиры с выходами ОК, либо по диоду в разрыв каждого выхода каждого регистра (40 штук).
Можно заменить на 74xx596 (открытый коллектор или сток) и добавить 5 резисторов.
Serg6845
22.11.2020, 15:10
Можно заменить на 74xx596 (открытый коллектор или сток) и добавить 5 резисторов.
резисторы должны быть в самом компе, так что не обязательно.
Вы правы, резисторы уже в спеке есть.
Похоже, 596 не очень-то и найдешь, а, если найдешь, то по какой цене?
А 40 диодов - это жуть
oistalker
22.11.2020, 20:41
есть один момент - в случае когда для опроса клавиш одновременно падают в 0 больше одного адреса - в такой схеме возникнет конфликт выходных уровней у активных регистров. чтобы этого избежать - нужно либо регисиры с выходами ОК, либо по диоду в разрыв каждого выхода каждого регистра (40 штук).
Не очень понятно к каким последствиям это ведёт. Если я правильно понимаю, то в этом случае при наличии на одном регистре 1, а на другом 0 на том же разряде, ток просто потечёт через OD вход (или не потечёт, по идее там встроенный диод в самом полевом транзисторе на выходе есть). Я эту схему на макетке собрал и проверил на самопальном клоне, ничего не греется вроде и видимых глюков нет. 596 от 595 отличается только тем, что 595 есть 3 состояние, а по даташиту от TI выходы у них по одной и той же схеме сделаны.
А как работает джойстик?
Это на перспективу было, вообще-то, но сел - припаял 5 проводов к джойстику от Dendy и его тоже завёл. Просто вычитываю 8 бит состояния кнопок и подмешиваю их при выводе в регистры, на кнопки 6,7,8,9,0,Enter,L,SPC. Точно так же можно джойстик от Super Nintendo подключить, там внутренний регистр на 16 бит.
void init_gamepad(int pin_data, int pin_latch, int pin_clock)
{
pinMode(pin_data, INPUT_PULLUP);
pinMode(pin_clock, OUTPUT);
pinMode(pin_latch, OUTPUT);
digitalWrite(pin_clock, HIGH);
}
int get_gamepad_state(int pin_data, int pin_latch, int pin_clock)
{
digitalWrite(pin_latch, HIGH);
delayMicroseconds(JDELAY);
digitalWrite(pin_latch, LOW);
int keys_state = 0;
for (int i = 0; i < JSER_COUNT; ++i) {
delayMicroseconds(JDELAY);
digitalWrite(pin_clock, LOW);
keys_state <<= 1;
keys_state |= digitalRead(pin_data);
delayMicroseconds(JDELAY);
digitalWrite(pin_clock, HIGH);
}
return keys_state;
}
void fill_gamepad_matrix(int jstate)
{
gamepad_matrix[GP_K_A] = (jstate & 0x80)>0 ? false : true;
gamepad_matrix[GP_K_B] = (jstate & 0x40)>0 ? false : true;
gamepad_matrix[GP_K_SEL] = (jstate & 0x20)>0 ? false : true;
gamepad_matrix[GP_K_START] = (jstate & 0x10)>0 ? false : true;
gamepad_matrix[GP_K_U] = (jstate & 0x08)>0 ? false : true;
gamepad_matrix[GP_K_D] = (jstate & 0x04)>0 ? false : true;
gamepad_matrix[GP_K_L] = (jstate & 0x02)>0 ? false : true;
gamepad_matrix[GP_K_R] = (jstate & 0x01)>0 ? false : true;
}
Serg6845
22.11.2020, 21:01
Не очень понятно к каким последствиям это ведёт. Если я правильно понимаю, то в этом случае при наличии на одном регистре 1, а на другом 0 на том же разряде, ток просто потечёт через OD вход (или не потечёт, по идее там встроенный диод в самом полевом транзисторе на выходе есть).
в случае с 595 - тот регистр где "кнопка нажата" - будет тянуть в 0, остальные (где "не нажата") - в 1. что в итоге получится на выходе - это как повезет. ну и "неаккуратно как-то"...
Я эту схему на макетке собрал и проверил на самопальном клоне, ничего не греется вроде и видимых глюков нет. 596 от 595 отличается только тем, что 595 есть 3 состояние, а по даташиту от TI выходы у них по одной и той же схеме сделаны.
может мы разные даташиты смотрим? я у TI нашел 596 только в варианте 74LS596
https://www.ti.com/lit/gpn/sn74ls596
и там совершенно четко видна разница между 595 и 596, на стр. 1 внизу.
oistalker
14.03.2021, 00:21
Прошло несколько месяцев, этап сборки первой версии - выяснилось, что такой "концепт" работает в 48к бейсике, но перестаёт подавать признаки жизни, если активируется AY-3. Сел и нарисовал вариант схемы с защитными диодами и даже развёл, но вовремя одумался и не стал заказывать этого монстра. И в итоге пришёл к третьему варианту, в котором конфликт на выходах регистров решается с помощью приоритетного шифратора 74HC148, - при таком подходе, ситуации когда будут активированы несколько регистров, исключаются. На неделе приехали платы и шифраторы (второй раз заказывал, т.к. в первый раз китаец забыл их отправить вместе с другими микросхемами) - я это дело собрал и всё заработало, без каких либо доработок прошивки. Позапускал демки, игрушки, видимых проблем не заметил. Проверял, правда, только на Harlequin 128.
Если кому интересно, то
вот схема для Rev3: 74934
вот файлы для изготовления платы Rev3: 74935
вот прошивка c исходниками (фьюзы нужно лить такие High=0xDA Low=0xFF Ext=0x05) : 74936
Немного фоток:
Как это выглядело на рендере KiCad
http://i.imgur.com/AzoaJ4Ym.png (https://imgur.com/AzoaJ4Y)
Как это выглядит после сборки
http://i.imgur.com/lP2RgMDm.jpg (https://imgur.com/lP2RgMD)
http://i.imgur.com/xyR9Auom.jpg (https://imgur.com/xyR9Auo)
http://i.imgur.com/thNBwD5m.jpg (https://imgur.com/thNBwD5)
Подключал в стандартный коннектор для плоских шлейфов (сами шлейфы, по разумной цене, найти у меня не получилось вообще нигде) с помощью сочинённой из гребёнки 2.54 и ответной части, для них же, с плоскими контактами "под золото" - они отлично фиксируется между металлической частью и корпусом коннектора
http://i.imgur.com/keY6TmHm.jpg (https://imgur.com/keY6TmH)
PS.
- Формирование низких уровней на RESET и NMI сделано по нажатию CTRL+ALT+DEL и F5 (как у ZX-UNO)
- Джойстик использовал стандартный, от китайской NES c разъемом DB9, клавиши забиты 6,7,8,9,0 на крестовину и A, M на B, Sel на L, START на Enter
- Резисторы на линии данных джойстика не распаивал и прошивка пока поддерживает лишь геймпад от NES. Планирую в дальнейшем добавить поддержку геймпада от SNES и возможность переключать тип пада на лету
- Есть неприятный момент, контактные площадки для резисторов в KiCad делали жадины (а handsoldering - транжиры, видно по площадкам для ll4148), места под нанесение припоя с краёв практически нет. Поэтому красиво и надёжно запаять у меня получилось только с дополнительной помощью фена
oistalker, классная идея!
Я вот подумал, если есть зашифрованный адрес, то можно использовать SRAM типа 74hc670 с возможностью одновременной записи и чтения, только большего размера. Конечно, 595 самые дешёвые и распространенные, но может быть есть что-то подходящее.
Можно и обычную маленькую SRAM взять, только нужно как-то урегулировать запись и чтение чтобы не было слишком короткого строба записи. Можно писать в память сразу после строба чтения.
oistalker
22.10.2021, 23:46
oistalker, классная идея!
Я вот подумал, если есть зашифрованный адрес, то можно использовать SRAM типа 74hc670 с возможностью одновременной записи и чтения, только большего размера. Конечно, 595 самые дешёвые и распространенные, но может быть есть что-то подходящее.
Можно и обычную маленькую SRAM взять, только нужно как-то урегулировать запись и чтение чтобы не было слишком короткого строба записи. Можно писать в память сразу после строба чтения.
Тут основная идея в том, что SPI в микроконтроллере аппаратный и работает на достаточно большой частоте, так что можно обеспечить минимальный инпут лаг. Если же взять что-нибудь типа IDT7130, учитывая количество свободных пинов на контролере, нужно будет использовать защёлки для фиксации адресов и параллельных данных и отдельно формировать импульсы записи. Тогда уж проще сразу CPLD использовать, но HC595 проще купить и нет проблемы с залоченными пинами jtag, как у MAX7000 из Китая
https://i.ibb.co/ZmwL6yL/IMG-20211023-075624.jpg (https://ibb.co/gVXjMsj)
Думаю такая схема должна работать.
1. После сброса МК заполняет 256 байт памяти единицами.
2. Шины адреса и данных МК переводятся в режим входа с резисторами подтяжки. Внешние резисторы подтяжки могут не понадобиться.
3. Когда МК получает данные с клавиатуры сразу же пишет измененный байт в память. Обновляются только 8 байт по адресам сканирования: 0b1111_1110, 0b1111_1101, 0b1111_1011 и т.д. Возможно что даже не будет никаких проблем с мусором на шине данных так как алгоритм опроса клавиатуры спека подавит данный "дребезг контактов". Но более вероятно что придется запрещать запись в память во время чтения клавиатуры. Для этого МК должен проверить наличие строба чтения клавиатуры перед записью в память. Цикл чтения порта z80 при частоте 3,5 МГц составляет 700 нс. Этого достаточно для того чтобы завершить предыдущий цикл записи, (при условии что память достаточно быстродействующая, скажем 100 нс) и считать данные. Конечно, критически важный код записи в память нужно максимально оптимизировать.
4. Ещё остаётся вариант: отслеживать строб чтения и писать в память сразу после него. Времени для записи остаётся более чем достаточно, даже если z80 подряд выполняет операции IN будет примерно 10 тактов z80 между стробами чтения.
Отличный проект, спасибо!
Единственный быстрый контроллер, построенный на выпускаемой сегодня элементной базе.
Захотелось в качестве микроконтроллера использовать atmega8, переписал прошивку над неё на на ассемблере (точнее, на своём недо-языке the Rat), что позволило ощутимо сократить размер кода (и, теоретически, уменьшить инпут лаг).
Исходники и прошивка тут: https://github.com/trol73/avr-zx-spectrum-keyboard-595
Reset, NMI и сложные клавиатурные макросы пока не добавлял (мне они сейчас не к чему), работу с геймпадом тоже (пока не на чем отлаживать).
В будущем есть желание переделать схему на работу с геймпадами Sega / NES с автоопределением. Свободные пины у атмеги остались, можно будет второй разъём геймпада добавить.
Powered by vBulletin® Version 4.2.5 Copyright © 2026 vBulletin Solutions, Inc. All rights reserved. Перевод: zCarot