I'm working on a project that will turn a Nintendo 64 controller into a Bluetooth HID device for Android. The code to send/receive data from the controller already exists, and I broadly understand it. The controller itself has 3 wires: +3.3V, Signal, and GND. The signal wire is connected to pin #2 of the Arudino Uno. I'm trying to understand the first snippet of code:
#include "pins_arduino.h"
#define N64_PIN 2
#define N64_PIN_DIR DDRD
// these two macros set arduino pin 2 to input or output, which with an
// external 1K pull-up resistor to the 3.3V rail, is like pulling it high or
// low. These operations translate to 1 op code, which takes 2 cycles
#define N64_HIGH DDRD &= ~0x04
#define N64_LOW DDRD |= 0x04
#define N64_QUERY (PIND & 0x04)
The comment about the external 1K resistor is confusing to me, as the example from which I am working doesn't use any external resistors. I understand how to use N64_HIGH, N64_LOW and N64_QUERY, but I don't understand the hexademical value 0x04.
My understanding of the first macro is that it will set the third bit to 0. The second macro will set the third bit to 1. This is the opposite of what I would expect -- why does the N64_HIGH macro set the bit to 0 instead of 1?
EDIT: Okay, did some searching, and these two macros will set the pin to input or output, respectively. According to the comment, this is like setting the output to high or low. Can someone explain how this works to me?
You use PORTD along with DDRD to set an output pin level.
PORTD maps to Arduino digital pins 0 to 7
DDRD - The Port D Data Direction Register - read/write (sets pins to input or output)
PORTD - The Port D Data Register - read/write. (Makes a pin, that has been set to an output, to HIGH or LOW)
PIND - The Port D Input Pins Register - read only (reads the current state of a pin.)
I'm working on a project that will turn a Nintendo 64 controller into a Bluetooth HID device for Android. The code to send/receive data from the controller already exists, and I broadly understand it. The controller itself has 3 wires: +3.3V, Signal, and GND. The signal wire is connected to pin #2 of the Arudino Uno.
Note that the device is a 3.3V device - so when connected to an Arduino 5V pin you have
to take special precautions to never drive that pin HIGH as the 5V pin would damage the
Nintendo controller.
The solution is to use open-drain output - that means the Arduino pin is either floating
or driven LOW. A pullup resistor (prob in the controller) pulls the line up to 3.3V if
the Arduino pin is floating.
The way you drive open-drain is to switch the pin between an input and an output,
all the time with it held LOW (being LOW as an input of course does nothing).
Note that this direct port manipulation isn't fully general - if you are using
N64_LOW and N64_HIGH from interrupt routines as well as the main code
then there will be issues and pinMode () is needed.
Thanks, MarkT!! That was very helpful. I've done some reading, and I understand how to use open-drain/open-collector. I have a couple of follow-up questions:
When reading the Signal wire with PIND & 0x04, am I correct in thinking that HIGH will be 3.3V? What is the voltage threshold between HIGH and LOW on a 5V board? EDIT: Did some more searching, >=3.0V is HIGH and <=1.5 is LOW
Could I eliminate open-drain completely by moving to a 3.3V logic-level board, and just use PORTD to control my logic output?