Создание самодельных аксессуаров для Dendy

    Сначала я и не думал писать статью на эту тему, но похоже, что это уже часть целого цикла статей на Денди-тематику. И да, на этот раз речь в первую очередь именно про отечественную Денди, а не про оригинальные консоли — Famicom или NES. Просто я делал устройство в подарок одному человеку, который снимает очень интересные видеоролики про Денди, и ориентировался на совместимость именно с этим клоном.

    Дело в том, что и для Famicom, и для NES выходили самые разные аксессуары: 3D очки, клавиатуры, роботы, считыватели штрих-кодов, всякие игровые контроллеры и очень многое другое. До нас же дошёл только световой пистолет. Передо мной стояла задача собрать устройство, которое совмещало бы в себе разветвитель на четыре игрока (да, были такие игры) и Arkanoid-контроллер.




    Порты ввода-вывода


    Прежде всего стоит рассказать, как же работают с джойстиками игровыми контроллерами Famicom, NES и Dendy, и чем же они отличаются в этом плане.

    С точки зрения игр порты ввода-вывода представляют из себя два регистра с адресами $4016 и $4017, которые ассоциированы соответственно с двумя портами, куда всё и подключается. Но на стандартных контроллерах для чтения данных используется только один провод — D0, данные с которого соответственно доступны через младший (нулевой) бит в каждом из регистров: $4016.0 и $4017.0. Аналогично используется один провод на запись, его обычно называют STROBE (или LATCH), который сбрасывает счётчик внутри геймпада, и который доступен через запись в $4016.0 (да, для обоих контроллеров он общий).

    Проще говоря, чтобы получить состояние кнопок на первом контроллере надо сначала записать 1 в $4016.0, сразу же записать туда же 0, сбросив таким образом счётчик, а потом прочитать $4016 и $4017 восемь раз (для каждой из кнопок), получая данные о кнопках из младшего бита. Но для чего же остальные биты в этих регистрах, куда идут эти линии? Рассмотрим порт контроллера у NES:



    Да, на него на самом деле идут D3 и D4! Именно они и доступны через $4016.3, $4016.4 у первого порта и $4017.3, $4017.4 у второго, и именно они используются для нестандартных контроллеров.

    Что же касается его японского собрата — Famicom, там нет этих портов, да и сами игровые контроллеры не отсоединяются от консоли, но у него есть порт расширения, который представляет из себя разъём DB-15.



    Знакомо выглядит, правда? Да, когда китайцы проектировали нашу Денди (я сомневаюсь, что её проектировали у нас), и им нужно было сделать отсоединяющиеся контроллеры, они решили взять за основу именно порт расширения, ведь в нём есть контакты для второго контроллера, и он на Famicom расположен чуть правее центра. Им тут даже распиновку менять не пришлось. Что же касается первого контроллера, они взяли тот же DB-15, расположили его слева и поменять распиновку так, чтобы можно было подключать первый контроллер. И только его.

    Сравните сами передние порты у Famicom и у нашей Денди:



    Вот такая вот странная история этих пятнадцатипиновых разъёмов у геймпадов, которые используются в нашей стране.

    Но давайте посмотрим, что же выведено на этот порт расширения у Famicom?


    (скриншот с сайта wiki.nesdev.com)

    Да, на него идут ещё $4016.1 (на ввод), $4017.0-4 (на ввод), $4017.0-2 (на вывод), внешнее прерывание и даже звук! Я был очень приятно удивлён, когда разобрал Денди и увидел, что всё это есть и там:



    Правда, не во всех моделях, как выяснилось позже. Но если это есть, значит есть и полная совместимость с аксессуарами для Famicom, и их могут использовать соответствующие японские игры. Но напомню, что Денди — это очень странная смесь NES и Famicom, PAL и NTSC. Пираты выпускали для неё и японские, и американские игры, которые по сути на 100% совместимы, если не брать в рассчёт эти аксессуары и разный формат картриджей.

    Итого: в некоторых Денди есть все те же выводы, что и на Фамикоме, которые при этом включают в себя часть выводов доступных на NES. Отсутствует доступ к $4016.3 и $4016.4, но они используются крайне редко. В виде таблички для наглядности:



    Принцип работы аксессуаров


    Американский разветвитель на четыре игрока для NES называется Four Score представляет из себя простой набор сдвиговых регистров. Т.е. первые восемь чтений из $4016.0 дают данные из первого контроллера, а вторые восемь — из третьего. Аналогично $4017.0 даёт данные о втором и четвёртом контроллерах. Помимо этого при продолжении чтения устройство выдаёт свою сигнатуру, с помощью которой игра определяет, что подключен именно Four Score, а не что-то ещё. Получается, что такое устройство можно собрать из шести сдвиговых регистров (4021 или 74165), и оно будет работать на любой Денди, ведь для него не требуются дополнительные линии данных. Само собой, только с американскими играми, которые выходили для NES.

    Японский аналог для Famicom устроен гораздо проще. Третий и четвёртый контроллеры подключаются напрямую в порт расширения и доступны через $4016.1 и $4017.1. Соответственно для такого переходника нам уже нужен полноценный порт расширения у Денди, иначе поиграть вчетвером в японские игры не получится.

    Arkanoid-контроллер, как ясно из названия, используется для игры Arkanoid и представляет из себя ручку-крутилку и одну кнопку. Внутри же это аналого-цифровой преобразователь и сдвиговый регистр, который так же последовательно выдаёт положение ручки. Разница между японской и американской версией только в способе подключения. Японская версия игры читает положение ручки и состояние кнопки из $4016.1 и $4017.1, а американская версия из $4016.3 и $4016.4 соответственно. Получается, что для японского Арканоида нужен полноценный порт расширения, а для американского подойдёт любая денди, где работает световой пистолет (он использует те же выводы).

    Создание своего аксессуара


    Хотя сами по себе вышеперечисленные устройства имеют простую схему и собираются из простейших логических компонентов, для сердца устройства типа «всё в одном» я решил использовать ПЛИС. Тем более мне было высказано пожелание сделать там ещё и простейший переключатель-свитч, а мне хотелось сделать возможность менять местами кнопки A и B. Сначала я выбрал Altera EPM3064ATC100, но вскоре выяснилось, что 64 макроячейки мне не хватит, и выбор пал на EPM3128ATC100, где уже 128 макроячеек.

    Если уж на то пошло, я решил совсем не мелочиться и поставить в устройство ещё и какой-то экран, на котором показывались бы текущий режим и меню с настройками, к тому же у меня давно валялся без дела один знакосинтезирующий «16x2» дисплей. Вот для работы с ним уже нужен микроконтроллер, и я выбрал ATMEGA16.

    Мне всегда было сложнее всего придать устройству приятный внешний вид. Всё-таки я программист, а не дизайнер, но именно при изготовлении устройства в подарок хотелось сделать его максимально красивым и удобным. Тем более это чуть ли не единственный способ как-то показать другим своё произведение искусства: фотографии и видео — это не то, по готовым схемам и 3D моделькам такие вещи воссоздают единицы, серийное производство наладить тяжело, а вот подарок — самое то.

    Итак, требования к внешнему виду были такие: четыре порта для стандартных DB-15 контроллеров от Денди, четыре кнопки для их выбора и настройки, кнопка «режим», кнопка «настройки», удобная ручка для Arkanoid и кнопка для него же, которые должны располагаться достаточно удобно и не мешаться. Помимо этого хотелось сделать, чтобы активные порты подсвечивались светодиодами и как-то интуитивно связывались с соответствующими кнопками, логичнее всего при этом расположить разъёмы в ряд, но эти дурацкие DB-15 слишком огромные для этого. Помимо всего устройство должно удобно лежать в руках, ведь оно само по себе игровой контроллер для Arkanoid. В итоге я пришёл примерно к такому виду:



    Кнопки в ряд, порты друг над другом, ручка сбоку, кнопка для Arkanoid сзади слева.

    Получается, что места внутри достаточно много. Поэтому ПЛИС с разъёмами под провода и гнёзда я решил вынести на одну плату, а микроконтроллер с экраном и кнопками — на другую. Соединяются они при этом простейшим последовательным интерфейсом.

    Плата с ПЛИС (первая версия):



    Вторая плата:



    Код для ПЛИС я писал на Verilog. Для каждого режима он получается достаточно простым. В первую очередь для многих из них нам надо считать обращения к каждому из портов, т.е. импульсы на проводе clock:

    reg [4:0] counter1;
    reg [4:0] counter2;
    
    always @ (posedge strobe_in, posedge clock1_in)
    begin
    	if (strobe_in)
    		counter1 <= 1;
    	else if (counter1 < 31)
    		counter1 <= counter1 + 1;
    end
    
    always @ (posedge strobe_in, posedge clock2_in)
    begin
    	if (strobe_in)
    		counter2 <= 1;
    	else if (counter2 < 31)
    		counter2 <= counter2 + 1;
    end
    

    (простите, хабр не умеет подсвечивать Verilog)

    Где strobe_in — это strobe (один на оба порта), а clock1_in и clock2_in — это соответственно clock на каждом из портов. Внутри консоли стоит логика: clock = R/W nand (адрес == $4016/$4017), т.е. на clock логический ноль, когда консоль читает данные по соответствующему адресу.

    Режим имитации американского разветвителя на четверых игроков выглядит так:
    always @ (*)
    begin
    	// Strobe соединяем напрямую - входы с выходами
    	assign strobe_out[0] = strobe_in;
    	assign strobe_out[1] = strobe_in;
    	assign strobe_out[2] = strobe_in;
    	assign strobe_out[3] = strobe_in;
    
    	// Дёргаем clock у каждого геймпада в зависимости от того, в который раз читает данные консоль
    	clock_out[0] <= (counter1 <= 8) ? clock1_in : 1;
    	clock_out[1] <= (counter2 <= 8) ? clock2_in : 1;
    	clock_out[2] <= (counter1 > 8 && counter1 <= 16) ? clock1_in : 1;
    	clock_out[3] <= (counter2 > 8 && counter2 <= 16) ? clock2_in : 1;
    
    	if (counter1 <= 8)
    	// Первый контроллер
    		joy1_data_out[0] <= joy_data[0];
    	else if (counter1 <= 16)
    	// Третий контроллер
    		joy1_data_out[0] <= joy_data[2];
    	// Сигнатура
    	else if (counter1 == 20)
    		joy1_data_out[0] <= 0;
    	else
    		joy1_data_out[0] <= 1;
    	
    	// Второй контроллер
    	if (counter2 <= 8)
    		joy2_data_out[0] <= joy_data[1];
    	// Четвёртый контроллер
    	else if (counter2 <= 16)
    		joy2_data_out[0] <= joy_data[3];
    	// Сигнатура
    	else if (counter2 == 19)
    		joy2_data_out[0] <= 0;
    	else
    		joy2_data_out[0] <= 1;
    
    	// Неиспользуемые выводы оставляем в высокоимпедансном состоянии, они подтягиваются к VCC внутри самой консоли
    	joy1_data_out[1] <= 1'bZ;
    	joy2_data_out[4:1] <= 4'bZZZZ;
    end
    


    В режиме японского же разветвителя на четверых нужно просто соединить входы с выходами напрямую:
    always @ (*)
    begin
    	clock_out[0] <= clock1_in;
    	clock_out[1] <= clock2_in;
    	clock_out[2] <= clock1_in;
    	clock_out[3] <= clock2_in;
    
    	joy1_data_out[0] <= joy_data[0];
    	joy2_data_out[0] <= joy_data[1];
    	joy1_data_out[1] <= joy_data[2];
    	joy2_data_out[1] <= joy_data[3];
    
    	// Неиспользуемые выводы оставляем в высокоимпедансном состоянии, они подтягиваются к VCC внутри самой консоли
    	joy2_data_out[4:2] <= 3'bZZZ;				
    end
    


    Самым сложным оказалось сделать возможность менять местами кнопки A и B, ведь считываются они последовательно, т.е. нужно заранее знать значение B, когда консоль запрашивает A, но оно выдаётся как раз только после A. Сначала я думал как-то ускоренно считывать данные с контроллера, используя какой-то внешний тактовый генератор, но в итоге решил просто брать значение от предыдущего считывания. Это даёт задержку, но она абсолютно незаметна. Тем более игры обычно читают состояние кнопок по несколько раз подряд.

    Само собой, все эти режимы и настройки надо как-то задавать. Для этого я определил 12-битный регистр control, данные в который записываются через последовательное соединение, с дополнительным битом для проверки чётности:
    reg [11:0] control;
    reg control_parity;
    reg [11:0] control_receiver;
    reg [3:0] control_counter;
    
    always @ (posedge control_strobe, posedge control_clock)
    begin
    	if (control_strobe)		
    	begin
    		control_counter = 0;
    		control_parity = 0;
    	end else begin
    		if (control_counter <= 11)
    		begin
    			control_receiver[control_counter] = control_data;
    			control_parity = control_parity ^ control_data;
    		end;
    		if (control_counter < 12)
    			control_counter = control_counter + 1;
    	end
    end
    
    always @ (posedge strobe_in)
    begin
    	if (control_counter == 12 && !control_parity)
    		control = control_receiver;
    end
    


    Соответственно со стороны микроконтроллера код (весьма грязный) выглядит вот так:
    void control_send(uint16_t data)
    {
    	set_bit(CTRL_PORT, CTRL_STROBE_PIN); // Strobe
    	_delay_us(10);
    	unset_bit(CTRL_PORT, CTRL_STROBE_PIN); // Strobe
    	_delay_us(10);
    	int b;
    	char parity = 0;
    	for (b = 0; b < 11; b++)
    	{
    		if (data & (1<<b))
    		{
    			set_bit(CTRL_PORT, CTRL_DATA_PIN); // Data
    			parity ^= 1;
    		} else {
    			unset_bit(CTRL_PORT, CTRL_DATA_PIN); // Data
    		}
    		unset_bit(CTRL_PORT, CTRL_CLOCK_PIN); // Clock
    		_delay_us(10);
    		set_bit(CTRL_PORT, CTRL_CLOCK_PIN); // Clock
    		_delay_us(10);
    	}
    	if (parity)
    	{
    		set_bit(CTRL_PORT, CTRL_DATA_PIN); // Data
    	} else {
    		unset_bit(CTRL_PORT, CTRL_DATA_PIN); // Data
    	}
    	unset_bit(CTRL_PORT, CTRL_CLOCK_PIN); // Clock
    	_delay_us(10);
    	set_bit(CTRL_PORT, CTRL_CLOCK_PIN); // Clock
    	_delay_us(10);
    }
    


    В остальном в коде микроконтроллера нет ничего особенного: работа с дисплеем на контроллере HD44780, кнопки, светодиоды, простенькая менюшка и работа с аналого-цифровой преобразователем для определения угла поворота ручки.

    Я всё отладил, убедился в работоспособности и уже начал упихивать компоненты в корпус…



    Но перед закрытием крышки решил проверить на оригинальном Famicom, ведь с ним устройство тоже будет использоваться. Увы, режимы, где нужно было считать импульсы clock, работали неправильно. С помощью логического анализатора выяснилось, что с линии данных идут наводки на линию clock:



    Это помеха длительностью всего в несколько десятков наносекунд всё портит. Я решил посмотреть своим простеньким осциллографом, что же происходит на линии clock у Денди:



    А вот что там же у Фамикома:



    Видно, что эта линия подтянута к VCC, при чём очень сильно у Денди и весьма слабо у оригинального Фамикома. Я начал экспериментировать с обвеской. Вскоре стало ясно, что на результат лучше смотреть не логическим анализатором, а самой консолью. Пришлось вспоминать ассемблер для 6502 процессора, писать простенькую программу для тестирования и записать её на картридж:



    На ней сразу стало всё наглядно видно, а заодно можно было протестировать сразу все режимы, не меняя игры. ROM можно скачать тут.

    В итоге проблема была решена подтяжкой линий clock к VCC через резистор в 1кОм, конденсатором между clock и землёй в 22нФ и резисторами на 200 Ом в разрыв всех линий данных. Увы, пришлось травить новую плату (не фотографировал), но зато после этого сразу же всё заработало.

    Итоговый вид устройства:



    Во времена СССР я мог бы быть хорошим промдизайнером.

    Многие наверное захотят увидеть видео, но на данный момент подарок уже в руках нашей почты, а я снял только небольшую видеоинструкцию для конечного пользователя. Посмотреть её можно тут: www.youtube.com/watch?v=39beci7nE8w

    И если вас заинтересовала тематика работы разных игровых контроллеров и создания самодельных, мы как раз на эту тему сняли вторую серию нашего шоу «Пока все играют», где многое очень просто и наглядно объясняется для тех, кто совсем не в теме:

    http://www.youtube.com/watch?v=nG-QznTyQKA

    Информация по архитектуре этих консолей и аксессуаров бралась с сайта wiki.nesdev.com
    Полный код для ПЛИС на Verilog: pastebin.com/nt39ZGvH
    Ads
    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More

    Comments 32

      +1
      Кстати, а нету ли (случайно) способа заставить световой пистолет работать на ЖКхах?
        +1
        Есть, но это весьма сложно — надо как-то отслеживать положение пистолета в пространстве и обрабатывать видеосигнал в реальном времени.
          +1
          Насколько помню, оригинальный пистолет просто ловил момент, когда от начала кадра «видел» квадрат (если видел).
          Современные 4нс грей-грей мониторы вполне могут выдать картинку так же быстро, но надо корректировать задержку.

          Вопрос — можно ли откалибровать его (например, выстрелом в центр пару раз) под монитор, после чего пользовать?
            +1
            Да, он просто реагирует на свет от экрана. Проблема в том, что игра требует мгновенного получения ответа, тут задержку если только каким-то хитрым хаком игры делать. Более того, некоторые игры вроде как учитывают текущее положение луча на кинескопе, т.е. какая строка выводится на экран в данный момент.
            0
            цитирую Андрея:

            Сейчас есть аналоги пистолетов для же дисплеев.
            Если интересно, то посмотрите как работает guncon 3 для PS3.
            Там в комплекте два инфракрасных диодных фонарика, которые нужно закрепить в углах телевизора, а пистолет их отслеживает.
            И вот аналогичный проект сразу для pc www.arcadeguns.com/index.php?main_page=index
              0
              Мы с ним уже списались. Описанную выше задачу это не решает, для трекинга можно использовать обычный виимоут.
                0
                Для получения координат «стрельбы» используйте вимоут (со всеми калибровками и прочим). Для передачи этой «координаты» берите выходной видеосигнал, прогоняйте ее через плисину, и по нажатию на триггер формируйте компаратор «освещенности» в видеосигнале на требуемых строке/ах в капчурным видеосигнале. Данный метод будет работать 100% во всех случаях, даже в VGA дендике, который я купил и потрошу: forums.nesdev.com/viewtopic.php?f=9&t=12578#p149155
                PS Этот же метод легко адаптируем под Сегу.
                  0
                  Я ещё не умею работать с выходным сигналом :) Но похоже, что скоро придётся (для других целей).
                    0
                    Это не так сложно, как кажется на первый взгляд.
                      0
                      Так абсолютно про всё можно сказать, когда речь о технологиях 80х годов :)
        • UFO just landed and posted this here
            +2
              +4
              «Сюбор» или какой-то его аналог.

              image
                0
                У меня есть такая — киборд 003 называется. Правда она начала сбоить лет 10 назад, насколько помню, что-то с блоком питания случилось плюс постоянно отходил контакт там, где картридж вставлялся. А картридж, идущий в комплекте, был по-своему интересен. Там были текстовый редактор аля Word, электронная таблица аля Excel, обучение вычислениям в столбик, клавиатурные тренажеры, игра «Архитектор», где можно было строить дома, пасьянс «Косынка», и т. д. Ну и, разумеется, можно было играть во всякие Super Mario Bros и Battletoads, был бы картридж.

                image
                • UFO just landed and posted this here
                    0
                    А у меня была похожая и там на картридже был даже basic :)
                      0
                      Тож в детстве такую с бейсиком видел. Только сохранять некуда было программки ))
                  0
                  А в какие игры вчетвером можно было играть?
                  0
                  Не продадите контроллер с тактовыми кнопками?)
                    0
                    Если Вы про тот, что у нас в видео, то мы его разломали. Но я могу сделать другой.
                    +1
                    У меня был клон в виде летающей тарелки, вроде этой:
                    image
                    Только пистолет был немного иной, и, самое любопытное, один из гемпадов был беспроводной инфракрасный! Правда, работал он похуже проводного, подглючивал.
                      +1
                      Был у меня именно такой клон, и эти джойстики рука еще помнит, но они, к сожалению, 90е не пережили. Но крестовину пришлось продублировать на 4 кнопки для прохождения Clinger Winger в Battletoads.
                        0
                        Тоже была летающая тарелка, в детстве сильно впечатляла уникальность внешнего вида. В комплекте был черный картдридж похожего дизайна с 99 (999?) играми.
                        0
                        супер челенжем было бы подключение беспроводных джойстиков ( blutooth например) к фамикому \ снесику. Или того же пада от вии\вию.
                          +2
                          Ничего в этом «супер» нету. Сплошная рутина, поверьте.
                            0
                            Что угодно лучше с блютусом! А рутиной становится только если делал хоть раз.
                          0
                          Насколько помню, в начале 90х сам подключал 3 и 4 джойстики для японских игр, и возни было гораздо меньше — вывел на корпус два DIN-5, и распаял два джойстика на DIN-5. А распиновка была такой-же как и на 1-2 джойстики за исключением замены одной линии, адресной, как теперь понятно по схеме, тогда же я наткнулся на это случайно, замкнув пару выводов при поиске пропавшего контакта в джойстике.
                            0
                            Так я же в статье и написал, что они подключаются напрямую, без всякой схемы. У меня ПЛИС их напрямую коммутирует, просто нужно же ещё режимы выбирать.
                            0
                            Судя по всему не дешёвое решение получилось. Не подскажете, ПЛИСину какуб использовали и сколько стоит такой чип?

                            Only users with full accounts can post comments. Log in, please.