Вход

Просмотр полной версии : Безвейтовый контроллер 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)

IanPo
21.11.2020, 22:38
Идея интересная, я бы только сигналы 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 штук).

IanPo
22.11.2020, 11:11
Можно заменить на 74xx596 (открытый коллектор или сток) и добавить 5 резисторов.

Serg6845
22.11.2020, 15:10
Можно заменить на 74xx596 (открытый коллектор или сток) и добавить 5 резисторов.

резисторы должны быть в самом компе, так что не обязательно.

IanPo
22.11.2020, 16:08
Вы правы, резисторы уже в спеке есть.

Похоже, 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), места под нанесение припоя с краёв практически нет. Поэтому красиво и надёжно запаять у меня получилось только с дополнительной помощью фена

Helbr
22.10.2021, 21:22
oistalker, классная идея!

Я вот подумал, если есть зашифрованный адрес, то можно использовать SRAM типа 74hc670 с возможностью одновременной записи и чтения, только большего размера. Конечно, 595 самые дешёвые и распространенные, но может быть есть что-то подходящее.
Можно и обычную маленькую SRAM взять, только нужно как-то урегулировать запись и чтение чтобы не было слишком короткого строба записи. Можно писать в память сразу после строба чтения.

oistalker
22.10.2021, 23:46
oistalker, классная идея!

Я вот подумал, если есть зашифрованный адрес, то можно использовать SRAM типа 74hc670 с возможностью одновременной записи и чтения, только большего размера. Конечно, 595 самые дешёвые и распространенные, но может быть есть что-то подходящее.
Можно и обычную маленькую SRAM взять, только нужно как-то урегулировать запись и чтение чтобы не было слишком короткого строба записи. Можно писать в память сразу после строба чтения.

Тут основная идея в том, что SPI в микроконтроллере аппаратный и работает на достаточно большой частоте, так что можно обеспечить минимальный инпут лаг. Если же взять что-нибудь типа IDT7130, учитывая количество свободных пинов на контролере, нужно будет использовать защёлки для фиксации адресов и параллельных данных и отдельно формировать импульсы записи. Тогда уж проще сразу CPLD использовать, но HC595 проще купить и нет проблемы с залоченными пинами jtag, как у MAX7000 из Китая

Helbr
23.10.2021, 08:51
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 между стробами чтения.

Trol73
24.09.2025, 23:15
Отличный проект, спасибо!
Единственный быстрый контроллер, построенный на выпускаемой сегодня элементной базе.
Захотелось в качестве микроконтроллера использовать atmega8, переписал прошивку над неё на на ассемблере (точнее, на своём недо-языке the Rat), что позволило ощутимо сократить размер кода (и, теоретически, уменьшить инпут лаг).
Исходники и прошивка тут: https://github.com/trol73/avr-zx-spectrum-keyboard-595

Reset, NMI и сложные клавиатурные макросы пока не добавлял (мне они сейчас не к чему), работу с геймпадом тоже (пока не на чем отлаживать).
В будущем есть желание переделать схему на работу с геймпадами Sega / NES с автоопределением. Свободные пины у атмеги остались, можно будет второй разъём геймпада добавить.