자바스크립트를 활성화 해주세요

PS2 듀얼쇼크 컨트롤러 호스트(리더) 구현 및 분석

 ·   ·  ☕ 15 min read  ·  ✍️ Yogo

2007년 초쯤 마이크로프로세서(이하 MCU) 스터디를 하면서 주로 해외에서 하드웨어 관련 정보를 찾아보던 도중 우연히 어느 일본인이 개인 홈페이지에 플레이스테인션2(이하 PS2) 듀얼쇼크2 컨트롤러(이하 듀속 또는 DS2) 시그널을 분석해서 공유한 페이지를 발견하게 됩니다.

관련 정보를 확인 한 이후 부터는 딱히 쓸데는 없었지만 DS2를 어떻게든 MCU에 연결해서 써먹어 보고 싶은 생각이 간절했습니다. 마침 사촌동생에게 PS2를 빌려서 사용하고 있었기 때문에 컨트롤러도 있겠다 연장선도 따로 구매한 것이 있어서 연장선을 중간에 단선시켜서 별도로 핀을 뽑아낸다면 MCU에 DS2를 연결이 수월할 수 있을거라고 판단이 되었습니다.

그래서 MCU에서 DS2 컨트롤러의 값을 읽을 수 있도록 호스트 에뮬레이션을 하기로 결정하고 실행에 나섰습니다.
그리고 결국 구현에 성공을 했는데요.

벌써 14년전으로 오래된 일이라 작업했던 상황이 모두 기억이 나지 않지만 예전 기억과 추억을 정리하는 측면에서 분석 위주로 글을 남겨볼까 합니다.

당시엔 관련 정보를 찾아보기 힘들었었는데, 현재에는 PS2, DS2 관련 내용이 많아서 몇가지 페이지나 사이트를 참고하여 수월하게 정리가 가능했습니다. 가급적 비 전공자분들도 보는데 불편함이 없도록 내용을 작성해보겠습니다.

DS2 컨트롤러 특징

DS2 컨트롤러는 디지털 키와 아날로그 조이스틱의 구분, 그리고 범퍼와 트리거로 구성된 구조 등현재 유행하는 컨트롤러들의 가장 기본 틀이 되는 구조를 가지고 있습니다.

전체의 키 맵은 디지털 상, 하, 좌, 우, select, start, 세모, 네모, 동그라미, 엑스, 2개의 아날로그 스틱(LX, LY, RX, RY)과 각 스틱 누름(L3, R3), 각각 2개의 범퍼(L1, R1)와 트리거(L2, R2)로 구성된 컨트롤러이고 피드백 진동 모터를 2개 탑재하고 있습니다.

DS2는 별도로 하나의 특수 버튼을 포함하는데요 중간에 디지털/아날로그 모드 선택이 가능한 버튼이 포함되어있습니다. 디지털은 말그대로 디지털 입력만 전용으로 받는 모드이고, 아날로그 모드는 좌우 아날로그 조이스틱 값을 추가로 사용하는 모드입니다. 지금이야 아날로그 버튼이 일반적이지만 당시에는 아날로그 버튼을 지원하지 않는 게임도 많았기 때문에 구분을 한 것이 아닐까 예상이 됩니다. 그리고 컨트롤러에 명시적으로 표시는 안되어있지만 컨트롤러 내부적으로 아날로그 모드에서 추가적으로 듀얼쇼크2 네이티브 모드(Dualshock 2 Native Mode)라는 것이 있습니다.

네이티브 모드의 경우 특수하게 디지털 버튼의 누르는 압력 감지가 가능한 모드인데요. 현재 일반적인 게임 컨트롤러의 경우 트리거 버튼이나 좌우 아날로그 조시스틱만 아날로그 값으로써 입력이 가능한데, 네이티브 모드의 경우 일반 버튼도 누르는 세기에 따라 압력 감도 구분이 가능합니다. 특정 PS2 게임에서 ‘버튼을 세게 누르세요’라는 인 게임 메시지를 표시하는 게임들이 있는데, 일반적인 컨트롤러 구조만 생각했을 때에는 선뜻 이해가 되지 않았으나 실제로 세게 누름이 인식된다는 것이 신기했었습니다.

이러한 특징이 가능한 것은 대부분 일반적인 컨트롤러에서 디지털 버튼의 눌림은 두 전극이 통전될 시 전원 논리 값 변화(on, off)만 감지하는데 반해, DS2의 경우에는 누르는 압력에 의한 전도성의 차이1 감지가 가능하기 때문입니다.

Dualshock2 Port 구조

아래 그림?은 DS2 커넥터를 바라본 시점에서 포트 이미지를 텍스트로 구성2한 것 입니다.

  1  2  3   4  5  6   7  8  9
-------------------------------
| o  o  o | o  o  o | o  o  o |  (at the Controller)
\_____________________________/
Pin Name Direction Description
1 DATA IN Data
2 CMD OUT Command
3 +7V OUT 7.6VDC
4 GND Ground
5 VCC OUT Vcc (3-5 VDC)
6 /ATT OUT ATT select
7 CLK OUT Clock
8 N/C Not connected\
9 /ACK IN Acknowledge

DS2은 총 9개의 핀으로 구성된 포트를 가지고 있습니다. 표에서 Direction 기준은 PS2 본체 기준이며, 전압 또는 데이터 흐름(논리 변화 값) 방향이라고 보시면 됩니다.

9핀중 3, 4, 5번은 전원과 관련된 핀이고 1, 2, 6, 7, 9번 핀은 통신과 관련된 핀입니다.

먼저 통신 핀 구성을 살펴보면 전자제품 개발쪽 일을 하시거나 회로쪽 관심 있으신 분들은 알겠지만 임베디드 환경에서 호스트 프로세서와 장치(Peripheral)간 통신을 할 때 사용되는 방식인 SPI(Serial Peripheral Interconnect)3와 유사하다는 것을 확인하실 수 있습니다. 다만 예외적으로 9번 ACK핀이 존재하기 때문에 일반적인 SPI와도 다르다는 것도 확인할 수 있습니다. ACK는 데이터 전송(또는 교환)이 정상적으로 되었음을 알리거나 다음 커맨드 또는 데이터를 받을 준비가 되었음을 알리기 위해서 보내는 신호입니다. 실제로 호스트 에뮬레이션 구현 시 정해진 시퀀스와 타이밍대로 통신을 하면 ACK 라인이 없어도 컨트롤러와 데이터를 주고 받는데는 문제가 없습니다. ACK를 N/C 처리하면 사실상 SPI 동일합니다.

다음으로 전원 관련 핀을 살펴보면 4, 5번 핀으로 컨트롤러에 메인 전원을 공급합니다. 3번 핀을 보면 예외적으로 높은 전압을 추가로 인가 하도록 되어있습니다. 3번 핀은 DS2 내부의 모터 구동을 위한 추가 전원입니다. 권장 전압은 7 ~ 9V 이지만 실제로는 5v나 더 낮은 전압으로도 동작은 가능했습니다. 대신 진동 모터 구동을 인한 전원이므로 메인 전원과 분리가 안되어있거나 또는 호스트측에서 전류를 충분히 제공하지 못하면 전압 강하가 발생할 수 있고, 이는 오동작 내지 디바이스가 리셋 될 수 있기 때문에 진동 기능을 사용하고자 전원을 제공할 때에는 주의해야합니다. 진동 기능을 사용하지 않는다면 불필요한 라인이 되므로 과감히 N/C 처리를 해도 컨트롤러의 입력값을 읽어오는 동작에는 문제가 없습니다.

참고로 6, 9번 핀을 보면 핀 이름에 /(슬래시)가 붙은 것을 볼 수 있습니다. 비 전공자들을 위해서 간략하게 설명드리자면 Active Low라는 의미를 나타내기 위한 표시입니다. 전자 회로에서 통신의 신호 논리 값을 high, low 또는 1, 0 등으로 표시를 많이 하는데, 논리 값이 low 상태가 될 때 특별한 동작이나 이벤트 발생한다라는 것을 명시적으로 나타내기 위해 사용되는 표시입니다.

이 경우에는 6번 핀의 논리 신호가 low가 되면 PS2가 ‘너랑 통신을 할거야’ 라고 DS2에 알려주는 용도이고, 9번핀은 논리 신호가 low가 되면 DS2가 PS2에게 ‘데이터 잘 받았어, 다음 데이터를 받을 수 있어’라고 알려주는 용도로 사용됩니다.

조금 더 자세한 특성 정보는 Interfacing a PS2 (PlayStation 2) Controller4 페이지에서 확인 하실 수 있습니다.

통신 라인 및 시그널 분석

Overview
      ____                                                              _____
 SEL-     |____________________________________________________________|     
      ______        ____        ____        ____        ____        _________
 CLK        ||||||||    ||||||||    ||||||||    ||||||||    ||||||||         
      _______________________________________________________________________
 CMD       X  01h   XXXX  42h   XXXX  00h   XXXX  00h   XXXX  00h   XXXX     
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~     
           _____________________________________________________________     
 DAT  -----XXXXXXXXXXXXX   ID   XXXX   5Ah  XXXX  key1  XXXX  key2  XXXX-----
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~     

 ACK- ---------------|_|---------|_|---------|_|---------|_|-----------------

Top command. First comminucation(device check)
      ____                                                                   
 SEL-     |__________________________________________________________________
      ______   _   _   _   _   _   _   _   __________________   _   _   _   _
 CLK        |_| |_| |_| |_| |_| |_| |_| |_|                  |_| |_| |_| |_| 
      __________                                                  ___        
 CMD            |________________________________________________|   |_______
                                                             ____            
 DAT  -----XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX    |___________
                                                                             
 ACK- ----------------------------------------------|___|--------------------

	X = none, - = Hi-Z

통신 시퀀스 다이어그램도 PS2 관련 텍스트5를 참고하여 두루넷, 메가패스 시절 감성으로 구성된 다이어 그램입니다. 참고로 해당 다이어그램에 표시된 것은 디지털 모드 기준이며 분석도 디지털 기준으로 설명합니다.

라인 구성

먼저 시그널 라인 구성을 보면 앞서 언급했듯이 ACK만 제외하면 SPI와 동일합니다. 레퍼런스 페이지마다 포트 구성에 적인 핀 이름과 다이어그램에 사용된 라인 이름의 차이는 있지만 SEL(Select)은 용어 그대로 특정 디바이스(여기서는 DS2)를 선택하기 위한 라인입니다. (임베디드 환경에서는 CS: Chip Select 라고도 자주 사용함) CLK(Clock)는 통신을 하기 위해 제공되는 라인으로써 데이터 라인들은 클럭과 동기화 되어 논리 신호값을 변경하고 읽게 됩니다. 당연한 이야기지만 클럭의 Frequecy가 높을 수록 논리 값을 빠르게 변경 할 수 있고 이는 곧 통신 속도도 빨라짐을 의미합니다. 통상 250kHz ~ 500kHz의 클럭 속도를 가진다고 합니다. CMD, DAT는 실질적인 데이터를 주고 받는 라인으로서 데이터 전송방향에 따라 CMD는 formal한 표현으로는 MOSI(Master Out/Slave In) 라인에 해당하고, DAT는 MISO (Master In/Slave Out) 라인에 해당합니다.

시그널 분석

상단 다이어그램을 보면 SEL 라인이 low로 떨어질 때 통신이 시작되고, high가 되면 통신 사이클이 종료되는 것을 볼 수 있습니다. 일반적으로 Master/Slave 관계의 통신 방식에서는 통신을 하고자 하는 디바이스 SEL 신호를 low로 낮추는 것을 시작으로 통신을 시작하게 됩니다. 다이어그램을 보면 SEL 신호가 high가 되기 전까지 PS2는 총 5바이트 CMD를 전송하고, 동시에 4바이트 DAT를 수신하는 것을 볼 수 있습니다. 그리고 그 사이사이 1바이트 통신이 완료될 때 마다 DS2는 ACK라인을 low ~ high로 일정시간 변화를 주면서 1바이트 송/수신이 완료되었음을 PS2에게 전달하고 있고, 마지막 ACK는 보내지 않아서 총 4번의 ACK만 보내는 것을 확인할 수 있습니다.

일반적으로 디바이스나 내부 Chip 간 통신에서는 커멘드 전송 - 데이터 수신 - 커맨드 전송 - 데이터 수신(CMD - DAT - CMD - DAT …)과 같이 핑퐁(Ping Pong) 스타일로 주고받는 반이중 통신(half duplex)을 하는 경우가 많은 편입니다. PS2와 DS2는 일반적인 핑퐁 스타일과 달리 시작 커멘드 전송 - 다음 커멘드 전송/데이터 수신 - 다음 커멘드 전송/데이터 수신(CMD - CMD/DAT - CMD/DAT …)과 같이 커맨 전송과 데이터 수신을 동시에 하는 전이중 통신(full duplex) 방식을 취하고 있습니다.

버튼 입력 정보를 얻기 위해서는 컨트롤러 부터 적어도 4바이트 데이터를 수신하고 있으므로, 만약 반이중 통신 방식이었다면 커맨드 포함 전체 통신 길이가 8 bytes 정도 되겠지만, 전이중 방식을 채용하여 처음과 마지막을 제외하고는 커맨드와 데이터를 동시 주고 받고 있기 때문에 시간 기준으로 5 bytes 정보만 교환하고 있으므로 반이중 방식 대비 상대적으로 효율적인 통신을 하고 있는 것을 볼 수 있습니다. 물론 중간에 ACK 신호를 별도로 보내고 확인하는 시간이 있기 때문에 효율이 월등히 좋다고는 할 수 없지만 적어도 반이중 통신보다는 적은시간에 1 사이클을 완료가 가능한 것을 볼 수 있습니다.

추가로 ACK 관련하여 만약 반이중 통신 방식이었을 경우에는 핑퐁 스타일로 데이터를 주고 받기 때문에 DAT 데이터를 수신받는 것 자체가 ACK 역할을 대신할 수 있어서 별도의 ACK 라인데 대한 필요성이 상대적으로 낮은데요, 전이중 통신 방식에서는 커맨드 전송과 데이터 수신을 동시에 하기 때문에 Slave(DS2) 측에서 커맨드를 잘 받았는지 또는 다음 커맨드를 보내도 괜찮은지에 대한 타이밍 체크를 좀 더 명확하기 위해서 별도 ACK 핀을 추가한게 아닐까 하는 예상을 해봅니다.

그리고 다이어그램 상으로는 확인할 수는 없는 내용이지만 PS2와 DS2 통신 시 비트 전송 순서는 일반적으로 많이 사용되는 MSB(Most Significant Bit)와 달리 LSB(Least Significant Bit) 방식으로 통신을 합니다. 독자규격을 사랑하는 소니 아니랄까봐 SPI에 ACK 라인을 넣은 것도 모자라 LSB를 채용하는 행보를 보여줍니다. 참고로 비전공자분들을 위한 부연설명을 드리자며 Byte 기준 첫번째 비트 부터 전송하면 LSB, 마지막 비트부터 낮은 비트 순서대로 전송하면 MSB 입니다. 예를 들어 16진수 0x7F는 2진수로 01111111 로 표시할 수 있는데요, 여기서 젤 낮은 비트는 가장 오른쪽에 있는 값 입니다. LSB 방식으로 전송하면 젤 오른쪽부터 1-1-1-1-1-1-1-0 순서대로 전송을 하고, MSB라면 젤 왼쪽 비트부터 0-1-1-1-1-1-1-1-1 순서대로 전송을 하게 됩니다.

통신 속도

앞 부분에서도 언급했지만 클럭은 250 ~ 500kHz로 PS1은 250kHz, PS2 500kHz 속도의 클럭으로 동작한다고 합니다. 1 클럭당 1bit 정보 교환(논리값 변화)이 가능하므로 500KHz는 500Kbps(Bit Per Second)와 동일하며 Byte 기준으로 하면 전송속도(baud rate)는 500k / 8 = 62.5k Bps(Byte Per Second)가 되겠습니다. 디지털 모드의 경우 송/수신 합쳐서 5bytes 마다 1 cycle이 완료되므로 62.5k / 5 = 12.5k Cycle Per Second가 되고 1개의 DS2 컨트롤러 기준 초당 12,500 번 컨트롤러 입력 값을 읽어 올 수 있습니다. 아날로그 모드는 62.5 / 9 = 6.94k, 네이티브 모드는 62.5k / 21 = 2.98k 정도로 컨트롤러 입력값을 읽을 수 있게됩니다. 이는 그냥 단순 계산에 의한 예측치이므로 참고 정도만 하시길 바랍니다.

커맨드 및 데이터 시퀀스4

이번에는 PS2와 DS2 간 통신 시 주고 받는 커맨드와 데이터를 한번 살펴보겠습니다. 내용상 DS2의 버튼 입력값을 읽어오는 부분만 설명하고, 별도로 컨트롤러의 설정이나 상태를 확인하는 커맨드는 생략하고자 합니다. 자세한 내용은 참고 페이지를 확인하시기 바랍니다.

디지털 모드

#byte 1 2 3 4 5
Command 0x01 0x42 0x00 0x00 0x00
Data 0xFF 0x41 0x5A 0xFF 0xFF
Section Header Digital

디지털 모드에서 커맨드/데이터 교환 시퀀스 입니다. 순서상 1 ~ 3 바이트까지를 일종의 통신 헤더로 볼 수 있고, 4번째부터는 컨트롤러의 입력 데이터가 반환되는 것을 볼 수 있는습니다.

먼저 PS2에서 보내는 Command 기준에서 첫 번째 바이트 값인 0x01은 통신을 시작할 때 보내는 데이터로 항상 일정합니다. 두 번째 바이트는 설정에 따라 달라질 수 있지만, 컨트롤러를 입력 값을 읽어올 때에는 0x42를 사용합니다. 3번째는 의미없이 항상 0x00 값으로 유지하고, 4, 5번째에 값은 설정에 따라 달라질 수 있지만 컨트롤러의 피드백 모터 구동 여부와 세기를 결정 할 수 있습니다.

DS2에서 전송하는 Data 기준에서 두 번째 바이트 0x41 값은 컨트롤러의 mode를 나타내는 값입니다. 모드에 따라 상위 니블(바이트 기준으로 상위 4바이트, 예를 들어 0x7F의 상위니블은 0x7) 값이 달라지는데요. 디지털 모드는 (0x4), 아날로그는 (0x7), 설정은 (0xF)로 구분이 됩니다. 하위 니블은 헤더 이후 전송될 (DS2 기준) 바이트 수를 나타내는데, 단위가 16bit(즉 2바이트) 입니다. 그러므로 위의 0x41 값을 해석해보면 현재 컨트롤러는 디지털 모드에 2바이트 버튼의 입력 데이터를 전송할 것을 의미합니다. 만약 아날로그 모드라면 디지털 입력 값 외에 좌우 아날로그 조이스틱 축 변화량 4바이트(Left X-Axis, Left Y-Axis, Right X-Axis, Right Y-Axis)가 추가로 포함되서 0x73이 될 것이고, 네이티브 모드라면 디지털 입력, 아날로그 축 데이터 외에 부가적으로 디지털 버튼의 압력 값 12바이트를 포함하여 0x79 값이 됩니다.

디지털 모드에 4, 5번 바이트는 실제 컨트롤러의 버튼 눌림 여부를 나타내는 값 입니다. 각각 비트 별로 다음과 같이 버튼이 매핑되어 있습니다.

#bit of 4th byte 8 7 6 5 4 3 2 1
Button Map Left Down Right Up Start R3 L3 Select
#bit of 5th byte 8 7 6 5 4 3 2 1
Button Map X R1 L1 R2 L2

아날로그 모드

아날로그 모드는 기본적으로 5번째까지는 디지털 모드와 동일하고 2개의 아날로그 조이스틱 X, Y축 데이터를 추가로 반환합니다.

#byte 6 7 8 9
Analog Map RX RY LX LY

아날로그 스틱 Axis별 1바이트 값을 사용하고 있으며 중립 값은 0x80 입니다. 그러므로 좌, 우, 상, 하 각각의 약 127단계로 구분이 됩니다. 예를 들어 RX 기준 값이 0이면 오른쪽 아날로그 스틱 X 축의 가장 작은 값이므로 오른쪽 아날로그 스틱을 가장 왼쪽 기울였을 때의 값이고, 255면 오른쪽 아날로그 스틱를 가장 오른쪽으로 기울였을 때의 값이 됩니다.

네이티브 모드

네이티브 모드는 아날로그 모드에서 추가로 12바이트의 디지털 버튼 압력값을 추가로 반환합니다.

#byte 10 11 12 13 14 15 16 17 18 19 20 21
Analog Map Right Left Up Down X L1 R1 L2 R2

각 버튼당 1 바이트이므로 255단계의 압력 인식이 가능합니다.

호스트 구현

실제 구현에 대한 상세 설명이나 코드를 첨부하는 것은 내용자체가 너무 길어질 것 같아(사실 너무 오래전 일이라 작업기 자체가 가물가물 합니다.) 어떻게 작업을 했는지에 대해 간략히 남기는 것으로 대신하겠습니다.

당시 처음으로 호스트 에뮬레이션을 위해서 사용한 마이크로프로세서는 Microchip의 PIC16F877A(이하 877A)6 라는 8bit 프로세서 입니다. 간단한 스펙을 나열하면 다음과 같습니다.

  • ROM: 14KB
  • RAM: 368B
  • SPEED: 5 MIPS/DMIPS
  • DATA EEPROM: 256B
  • Digital Communication Peripherals: 1-UART, 1-SPI, 1-I2C1-MSSP(SPI/I2C)
  • Capture/Compare/PWM Peripherals: 2 Input Capture, 2 CCP
  • Timers: 2 x 8-bit, 1 x 16-bit
  • ADC Input: 8 ch, 10-bit
  • Number of Comparators: 2

877A는 Microchip 사의 8bit 계열 MCU에서는 Mid range 급에 해당하는 프로세서입니다. 현재 인기있는 ARM Cortex-M (32bit) 시리즈에 비하면 매우 평범한 스펙이지만, 당시에는 나름 좋은 스펙으로 출시된 미드레인지 제품이었습니다. 실제 많은 상용 전자제품 또는 산업용 컨트롤러 등이 단가 등 기타 이유로 매우 성능이 제한적이고 낮은 성능의 8비트 프로세서를 많이 씁니다.(심지어 4bit 쓰는 곳도 있다고.. 877A는 그에 비하면 선녀급) 당시에는 하드웨어 스터디용으로 구입해서 사용하고 있었기 때문에 구태여 다른 프로세서를 사용하지 않고 가지고 있는 것을 활용하기로 했습니다.

다만 877A를 사용하면서 몇가지 문제점이 있었는데요. 877A의 경우 SPI 관련 레지스터 설정이 하이엔드 급 MCU 보다는 제한적이어서 MSB, LSB 선택이 불가하고 오로지 MSB 방식 통신만 가능했습니다. 그리고 통신 클럭 속도 제어도 분주방식으로 MCU 메인 클럭에서 4, 8, 16, 32 등으로 나눈 속도로 통신이 가능했기 때문에 원하는 속도를 정확하게 설정하기 힘든 구조였습니다.(클럭의 경우 최대 속도만 초과하지만 않아도 됩니다만 초반에는 가급적 스펙과 유사하게 구현하여 혹시 모를 실패에 대한 가능성을 줄이고자 했습니다) 결국 877A 내부에 있는 SPI peripheral 자체를 활용하기에는 어려웠습니다.

그래서 일반 입출력 포트를 SPI 통신처럼 동작하도록 Software Driven 방식으로 같이 에뮬레이션 하여 호스트 구현을 진행했습니다.

사실 오래전 일이라 어떻게 작업했는지 디테일하게 생각은 나지 않지만, 며칠을 고생했던 것으로 기억이 납니다. 구현자체의 난이도 보다는 정확한 스펙 시트가 없는 상태에서 진행하는 작업이다보니 원하는대로 동작이 안될 때 어디서 문제가 있는 것인지 검증하는 것이 어려웠기 때문입니다.

예를 들면, 직접 구현한 SPI 에뮬레이션 자체가 문제가 있는 것인지?
호스트 구현에서 내가 빠뜨린 것은 없는지?
컨트롤러와 프로세서간 하드웨어 연결에는 문제가 없는지?
타이밍에 문제가 있는 것인지?
의심할만한 구간은 많고 실제 검증은 어렵다보니 어디서부터 어떻게 확인을 하고 무엇을 고쳐봐야하는지 감을 잡기가 매우 어려웠습니다.

결국 일일히 펙터 등을 수정 등을 반복하며, 다행히 삽질이 지쳐갈 때쯤 가까스로 구현에 성공하였는데요 신호를 read/write 하는 타이밍쪽 문제였던 것으로 기억합니다. 어쨌든 방학기간에 홀로 동아리방에 처박혀서 며칠을 고생하여 컨트롤러 입력값을 읽어오는 데 성공했을 때의 쾌감이란 말로 할 수 없을 정도로 기뻤었습니다.

막상 구현해놓으니 당장 어디 써먹을 데는 없었지만 성취감만으로 매우 만족할 수 있었습니다.

동작 화면

하도 오래전 일이라 동작화면을 남겨둔게 많지 않은데, 피쳐폰으로 찍어놓은 동작 영상이 남아있습니다.

졸업작품으로 막 출시된 Microhip 사의 16비트 프로세서를 활용해서 MP3, BMP 이미지, TXT 리딩이 가능한 멀티 플레이어를 만든적이 있는데, 거기에 부가적으로 테트리스 게임을 구현해서 넣었었습니다. LCD 터치로도 동작이 되지만 PS2 패드로도 조작이 가능하도록 했습니다.

구현예제

나중에는 기회가 되면 TETRIS나 멀티 플레이어 구현 및 작업기도 남겨볼까 싶은데요. 확실하지 않은데 메모리 아끼겠다고 맵을 bit 단위로 만들어서 적은 코드로 동작하게 만들고자 했던 기억만 조금 남아있습니다.

마치면서

이전에 어떻게 작업했었는지 정리차원에서 남긴 글인데 다시 보니 즐거운 추억입니다. 한편으론 학생때는 시간도 많고 열정도 많아서 이런저런 개인 스터디와 프로젝트 진행을 과감히 할 수 있었는데, 지금은 삶이 바쁘다는 이유로 지난 추억으로만 회상하고 돌아봐야하는 현실이 조금 아쉽습니다. 기회가 되면 시간을 내서라도 개인 스터디와 프로젝트를 진행하고 싶네요. 읽으시는 분들께도 잠시 즐거운 시간이 되었길 바라면서 마칩니다.