N64 to USB HID interface

Dependencies:   mbed

main.cpp

Committer:
igor_m
Date:
2011-09-25
Revision:
1:38815edb0ecb
Parent:
0:547c5459faa6
Child:
2:b38d6345dd14

File content as of revision 1:38815edb0ecb:


/*
N64 Controller Interface for the mbed.

by Igor Martinovski
March, 2011.

Function Mapping (from www.mixdown.ca/n64dev/)

Bit     Function
0        A
1        B
2        Z
3        Start
4        Directional Up
5        Directional Down
6        Directional Left
7        Directional Right

8        unknown (always 0)
9        unknown (always 0)
10        L
11        R
12        C Up
13        C Down
14        C Left
15        C Right

16-23   X value (signed)

23-32   Y value (signed)

Pinout:
Looking at the controller plug, flat side down.
Pin 1 (Left)    Ground
Pin 2 (Center)  Data**
Pin 3 (Right)   +3.3V*

(*)Note: The controller is supplied by 3.6V on the N64, but it seems to work fine on
the 3.3V provided by the mbed.

(**)Warning: The N64 controller must be connected to an open drain pin with a
pull-up resistor. The line must never be driven high by the mbed! If you are not
sure how to connect the controller safely, you may damage the mbed and/or
controller. You have been warned.
*/

#include "mbed.h"
#include "stdint.h"
#include "usbhid.h"
#include "IOMacros.h"

USBJoystick joystick;


/*
N64 Controller Interface for the mbed.

by Igor Martinovski
March, 2011.

Function Mapping (from www.mixdown.ca/n64dev/)

Bit     Function
0        A
1        B
2        Z
3        Start
4        Directional Up
5        Directional Down
6        Directional Left
7        Directional Right

8        unknown (always 0)
9        unknown (always 0)
10        L
11        R
12        C Up
13        C Down
14        C Left
15        C Right

16-23   X value (signed)

23-32   Y value (signed)

Pinout:
Looking at the controller plug, flat side down.
Pin 1 (Left)    Ground
Pin 2 (Center)  Data**
Pin 3 (Right)   +3.3V*

(*)Note: The controller is supplied by 3.6V on the N64, but it seems to work fine on
the 3.3V provided by the mbed.

(**)Warning: The N64 controller must be connected to an open drain pin with a
pull-up resistor. The line must never be driven high by the mbed! If you are not
sure how to connect the controller safely, you may damage the mbed and/or
controller. You have been warned.
*/

#include "mbed.h"
#include "stdint.h"

// Controller Commands

#define GET_STATUS          0x00
#define REQUEST_CONTROLS    0x01
#define READ_MEMPACK        0x02
#define WRITE_MEMPACK       0x03
#define READ_EEPROM         0x04
#define WRITE_EEPROM        0x05
#define RESET_CONTROLLER    0xff

#define T1                  24      // Corresponds to 1 us        
#define T2                  72      // Corresponds to 3 us

DigitalInOut inout(p14);            // Connect controller here
// using 220 ohm pull-up
Serial pc(USBTX, USBRX);
DigitalOut led(LED1);
uint8_t x, y;
volatile char bit_count;
union controls { /* A definition and a declaration */
    uint8_t array[4];
    uint32_t result_32;
} controls;

/** EINT3_IRQHandler
 */
void ISR(void);
extern "C" void EINT3_IRQHandler(void) {

    // The "event" is connected to pin p10 which is LPC1768 P0_1
    // so lets trap that and ignore all other GPIO interrupts.    
    // Test for IRQ on Port0.

    if (LPC_GPIOINT->IntStatus & 0x1) {
    // If P0_16/p14 rises, call atint()
        if (LPC_GPIOINT->IO0IntStatF & (1 << 16))  ISR();
    }
    // Clear this and all other possible GPIO generated interrupts as they don't concern us.    
    LPC_GPIOINT->IO2IntClr = (LPC_GPIOINT->IO2IntStatR | LPC_GPIOINT->IO2IntStatF);
    LPC_GPIOINT->IO0IntClr = (LPC_GPIOINT->IO0IntStatR | LPC_GPIOINT->IO0IntStatF);

}

void event_irq_init(void) {
    // Use macro to set p10 as an input.
    //p10_AS_INPUT; 
    // Enable P0_16/p14 for falling edge interrupt generation.
    LPC_GPIOINT->IO0IntEnF |= (1UL << 16);
    // Enable the interrupt.
    //NVIC_EnableIRQ(EINT3_IRQn);
}


// Temp array for controller data

/* void delay(unsigned int n) is used as a short delay to
   time the bit patterns. 1 n is roughly 0.042us on 96MHz CCLK
 */
void delay(unsigned int n) {
    unsigned int i;
    for (i=0; i<n; i++)
        ;
}

void ISR(){
    delay(48);
    if (inout.read()) controls.result_32 |= (1UL<< bit_count);
    else controls.result_32  &= ~(1UL << bit_count);
    bit_count++;
}

/* int receive(char *data_array, unsigned char n) is used to
   receive a bit stream of bits into an array of n bytes coming
   from the controller. This must be called immediately after
   sending any kind of request to the controller
 */

int receive(uint8_t *data_array, unsigned char n) {
       
    int i;
    bit_count=0;

    NVIC_EnableIRQ(EINT3_IRQn);

    while(bit_count<33){
        ;//Wait for Interrupts
        }
       led=1;
    NVIC_DisableIRQ(EINT3_IRQn);

        x=y=0;
        for (i=0;i<=7;i++) {
            if (controls.array[2] & (1 << i))
                x=x | (1 << (7-i));
            if (controls.array[3] & (1 << i))
                y=y | (1 << (7-i));
        }
        data_array[2]=x;
        data_array[3]=y;
    return n;
}


/* void send_byte(unsigned char byte) is used to send a single
   byte to the controller.
 */
void send_byte(unsigned char byte) {
    char i;
    //inout.output();           // Not sure about this.
    inout.write(1);             // Makes sure line is left high

    wait_us(500);
    for (i=0; i<8; i++) {
        if (byte & 128>>i) {
            inout.write(0);
            delay(T1);
            inout.write(1);
            delay(T2);
        } else {
            inout.write(0);
            delay(T2);
            inout.write(1);
            delay(T1);
        }
    }
    /* Send Stop Bit */
    inout.write(0);
    delay(T1);
    inout.write(1);
    delay(T1);

}

int main() {
    inout.mode(OpenDrain);           // Must use open-drain for N64 Controller!
    event_irq_init();
    uint32_t previous_result=0;                           // Used for the bit-shifting for x and y values
    send_byte(RESET_CONTROLLER);
              wait_ms(10);
    while (1) {
        wait_ms(10);
        previous_result=controls.result_32;
        send_byte(1);                // Send the request byte
        receive(controls.array, 4);           // Start receiving bit stream
        
        if (controls.result_32==previous_result) continue;
        
        
        pc.printf("%3d %3d %d %d\n ", controls.array[0], controls.array[1], (int8_t)controls.array[2], (int8_t)controls.array[3]);
        //pc.printf("%d\n",controls.result_32);
//joystick.joystick(controls.array[0],controls.array[1], controls.array[2], controls.array[3]);
    }

}