a man, a plan, a cake: nirvana

iPod Serial and the Nunchuk

I uploaded a new sample sketch for my iPodSerial library that uses the Wii Nunchuk to control the iPod. I used todbot’s WiiChuck adaptor to connect the Nunchuk to the Arduino.

The Wii Nunchuk has a joystick, from which you can read the X and Y axes, a Z button, a C button and the 3-axis accelerometer. I mapped the controls so that: left/right on the joystick is skip forward/backward; up/down on the joystick is scroll up/down; Z button is Play; c button is Ok/Select; and a tilt backward (using the Y axis of the accelerometer) is the menu button.

You could of course map them any way you wanted to.

Here’s a quick video of it in action (the Arduino is off-screen to the right).

iPod Serial and the iPhone

Bad News

I have discovered that I am unable to get Advanced Remote mode to work with the iPhone 3G or 3GS. I had been doing all my recent work on Advanced Remote mode with an iPod Photo so as not to put my iPhone through any pain. It was really hard to test before but I wrote an AdvancedRemote_ethernet example sketch (it's in the library in github) to help with that. Recently I spoke with Ben, who is doing some RFID work with a jailbroken iPhone. He could get his iPhone to receive serial commands but not transmit them, and the key for him ended up being the presence of the 500kOhm resistor on pin 21 - without it his app on the iPhone couldn't transmit to the serial port.

Because Ben had been asking me about it, I tried the Advanced Remote mode on my iPhone 3GS and then my wife's 3G. I was surprised to find that the iPhone sees the commands but it sends back a "feedback" response with error 4. The exact same code works perfectly with the old iPod Photo. At first I hoped this was because I'd removed the resistor on pin 21 - which wasn’t needed for the iPod Photo - so I put it back, but still no luck. Then I thought that perhaps the iPhone is fussier about the value of the resistor - I was using a 560kOhm and it's supposed to be 500kOhm - so I ordered some 500kOhm resistors from digikey. These arrived yesterday so I swapped the resistor, but I saw the same problem. So it looks like the resistor is needed for applications on an iPhone to be able to transmit serial data, but for the built-in iPod application there needs to be either something more than that or something instead of that.

I know the iPhone is
incredibly specific about the inputs it sees before it will charge itself through the dock connector, so I'm guessing there's something like that about it wanting to see something on some other pins before it's willing to be controlled via Advanced Remote mode too. It has to be possible because my car does it with my 3GS, and it's the kind where the car has a separate display and can show track information etc, so it must be using Advanced Remote mode. I may probe the cable that comes with my car if I can find some time.

Good News

The Simple Remote mode commands do work with the iPhone though. I wrote a SimpleRemote_ethernet example sketch and was able to go through the menus, change the volume, play/pause, etc. on my 3GS. The initial remote I had in my old car with the Easy button used this approach.

iPod Simple Remote Example

Today we’ll look at one of the example sketches that comes with my iPod Serial library. This one is for the Simple Remote mode, aka iPod Remote mode, aka Mode 2. Simple Remote mode provides serial commands that are the equivalents of the commands available through the physical buttons on the iPod. For the nitty gritty see the protocol wiki page on ipodlinux.org.

The SimpleRemote_with_Bounce example sketch sends the Play/Pause message when it sees a button is down and sends the “button released” message when it sees the button is up. This is the sketch I used in my own

This sketch uses the Arduino Bounce library to debounce the button. There’s a version that does the debouncing on its own, called SimpleRemote, but it’s more complicated and wouldn’t scale if you were to use it for more buttons.

Let’s take the example sketch line by line (mostly):

Line 7 pulls in the Simple Remote mode header file from the library. You need to have placed a copy of the iPodSerial library in your Arduino IDE’s libraries folder for this to work.

Line 8 pulls in the Bounce library. You need to have placed a copy of the Bounce library in your Arduino IDEs libraries folder for this to work.

Line 10 says we’re going to have our button connected to the Arduino’s digital I/O pin 5.

Line 11 sets the debounce interval to 20 milliseconds, meaning that the button has to stay up or down for 20 milliseconds before the Bounce library will decide that is really up or down.

Line 13 creates our Bounce object, which is what’s going to do the debouncing for us.

Line 14 creates our SimpleRemote object, which is what’s going to talk to the iPod for us.

Line 18 makes digital I/O pin 5 an input, so we can read from it to see if the button is up or down.

Line 21 enables digital I/O pin 5’s internal pull-up resistor. This sounds scary, but all it means to us is that we can connect a button between pin 5 and ground without any other circuitry, which is referred to as an active-low configuration. The means that the pin will read as LOW when the button is down (pressed) and HIGH when the button is up (released). That probably seem backwards but as long as we’re expecting it to work that way it’s not a problem.

Line 23 takes care of setting up the serial connection to the iPod.

Line 28 lets the SimpleRemote object take care of anything it needs to do with the iPod. This needs to be in our loop() function.

Line 30 asks our Bounce object if there has been a change in the state of the button. That is, has the button just been pressed or just been released.

Line 32 checks the new state of the button, now that line 30 has told us the button has just changed state. If the new state is LOW that means the button has just been pressed (since we’re using an active-low button configuration).

Line 34 will get executed if the button has just been pressed. It tells our SimpleRemote object to send the Play command, which toggles the iPod between Play and Pause, just like the physical Play / Pause button would.

Line 37 will get executed if the button has just been released. The Simple Remote protocol requires this so that the iPod knows when the button has been released. Because of this, press-and-hold behaviours of the physical buttons also work through Simple Remote mode. So, for example, if you press and hold the button using this sketch the iPod screen will fade to black after a few seconds, just like it would if you pressed and held the physical Play button.

And that’s it!

If you look in the library at the file SimpleRemote.h you can see the full list of commands that can be sent:

  • Play (the one we used in the example, that toggles between Play and Pause)
  • Volume Plus
  • Volume Minus
  • Skip Forward
  • Skip Backward
  • Next Album
  • Previous Album
  • Stop
  • Just Play (rather than toggling between Play and Pause)
  • Just Pause (rather than toggling between Play and Pause)
  • Toggle Mute
  • Next Playlist
  • Previous Playlist
  • Toggle Shuffle
  • Toggle Repeat
  • iPod Off
  • iPod On
  • Menu
  • Ok / Select
  • Scroll Up
  • Scroll Down

Expanding the example to work with more buttons is pretty simple. Let’s see what it would look like if we added volume plus and minus button support:

iPod Remote Part Deux

3/26/2010 UPDATE: Advanced Remote mode is not working for me with iPhone. See update post.
4/14/2010 UPDATE: See here if you have a v1.4 PodBreakout board.

I had been using my
iPod remote for a few months. It worked well and scratched the itch it was built to scratch. But in December I got a new car with iPod and Bluetooth integration. I also got rid of my despised Blackberry and switched to an iPhone. This meant I no longer needed to use my custom remote, so I placed it lovingly in my electronics drawer and forgot about it for a while.

Recently I was asked if I would present a talk at
Make: PGH about my experiences developing my Arduino iPod Serial library. I agreed, and it’s tentatively scheduled for the April meet-up. Someone also sent me an email asking for some help troubleshooting their build of a remote, so I was inspired to dig the remote out of the drawer. I also took a look at the library I’d created and decided that I really ought to finish what I’d started.

I already had a spare logic-level converter and PodGizmo from the original project, so I soldered them together and hooked them up to my
Mega. (The Mega is great for testing serial protocol stuff because it has four real serial ports, compared to the one on a regular Arduino. I built the library with debug hooks in it so that I could spit out the protocol data going back and forth between the iPod and the Arduino, and without that it would have been really hard to debug it.)

I discovered that the resistor connected to pin 21 isn’t needed. I also realized that I could use the iPod to supply the low-voltage power to the logic-level converter. This cleaned up the wiring considerably (click on the image to go to Flickr where there’s a full-resolution version):

On the left is a
Freeduino with an Ethernet Shield on top of it, but more on that later - the point is that you just need 5V, Ground and your Serial TX/RX lines on the Arduino side. The awful connections in the four wires between the logic-level converter and the PodBreakout board shouldn’t be there. They only exist because I tried out the suggestion here to skip the logic-level converter and put a 1KOhm resistor between the Arduino TX pin and the iPod RX pin. I verified with an EE friend that this would be okay and he said:

While not optimal, you should never see a problem with a 1k resistor. On TX_ARDUINO... (not RX_ARDUINO). What you're doing is relying on the protection diode of the iPhone to clamp the Voltage and sink some current. The resistor will do two things. 1) Limit the current possible to send into the iPhone (5V / 1k = 5mA max). Almost all digital protection circuits can handle 5mA for a few minutes at least. Therefore, even if you wire it up wrong, you will be very unlikely to fry anything. 2) Provide somewhere besides the protection diode in the iPhone to dissipate the power (V^2/R = 1.7*1.7/ 1k = 2.89 mW). 3mW isn't a lot of power for a diode, but it will help prevent the chip from wearing out prematurely.
Vih on the ATmega328 (Duemilanove) is 0.6*Vcc when Vcc is 5.0V. This means that the input signal needs to be above 3.0V to be guaranteed to be seen as a "1". There's usually a bit of guard-band on that spec. However, I would NOT put a resistor on the iPhone output to the Arduino (RX_ARDUINO). If you did, you'd start to see bit errors at higher bit rates. At 9600 baud, you shouldn't see anything unpleasant on either side of the bus.

As he said, it didn’t do any harm to my iPod, but unfortunately I was unable to get any communication to work using this method. I tried it a few times, even with just the Play/Pause sketch, which requires no response from the iPod, without luck. It could be that I did something wrong though. The logic-level converters are under $3 so I’m okay with continuing to use them.

Back in September I had two example sketches included in the library: a Simple Remote Mode one that did play/pause, which was what I was using in my car; and a proof-of-concept sketch for Advanced Remote Mode. This went with the just-proof-of-concept Advanced Remote mode support I had implemented. Over the last few weeks I have added full support for Simple Remote Mode, which was pretty easy, and near-full support for Advanced Remote Mode (no picture block support), which was a lot more complicated. I also refactored the library code because it needed to be done, and that sort of thing makes me happy.

I have been adding example sketches as I go, and I will talk about those in follow-up articles.