Interfacing the PIC32 with an Android device
Introduction
Learn to connect an Android device and a PIC32 microprocessor. This guide was developed with the NU32 (2012 version).
Getting Started
You'll need the following hardware:
- A PIC32 microprocessor (i.e. the NU32 development board)
- An Android device running at least version 2.2
- USB cables:
- Type-A to Mini-B cable (computer to PIC32)
- Type-A to Micro-B cable (computer to Android device)
- A spare USB cable with a Micro-B end (Android device to PIC32)
and the following software:
- Microchip's MPLAB X with the C32 compiler (download from Microchip's website)
- Eclipse (download from the Eclipse project's website -- Eclipse Classic recommended)
- Android SDK (download from the Android website and follow the instructions to link it to Eclipse)
It's optional, but you'll want the HD44780, a 2 by 16 character LCD with libraries available for the PIC32.
In addition, you'll need the starter code associated with this documentation, FILE_LINK_HERE. The code includes the String Passing Demo, a firmware/application pair that passes raw sequences of bytes back and forth, interpreted as strings. There's also the Android Sensor Demo, a firmware/application pair that shows you how to access the GPS, camera, touchscreen, and microphone of the Android device to collect data that may be useful for the PIC.
The PIC32 firmware is written in C and compiled with MPLAB X and C32; the Android applications are written in Java and are built with Eclipse. Be sure to take advantage of the features in MPLAB X and Eclipse. These IDEs can quickly rename variables (Ctrl-R in MPLAB X, Alt-Shift-R in Eclipse), jump to where a function is defined (hold Ctrl and click), and perform other refactoring that will save you time when programming.
Accessing USB on the PIC
First, you'll need a USB cable to connect your Android device to the PIC. You'll probably need the following:
- Spare USB cable with a Micro-B end
- (2) capacitors in the 1 uF range
- Soldering iron
- Red, black, green, and white wire
- Electrical tape
Cut the non-Micro-B end off your USB cable. Inside the outer insulation, you should see four wires: a red wire (VBUS), a black wire (GND), a green wire (D+), and a white wire (D-). Solder each stranded wire to a solid wire of the same color, and wrap the joints in electrical tape so they don't accidentally bump into each other.
On the NU32 board, you'll need to solder wires to the VBUS and VUSB pads right below the microprocessor.
Now, you'll need to wire everything up. Here's the diagram from the PIC32MX reference manual: Media:Pic32_usb_wiring.pdf. We can ignore VBUSON and wire VBUS directly to 5V. D+ is G2 and D- is G3 on the NU32. When you power on your development board and connect your Android device, the device should begin charging.
String Passing Demo
Unzip the folder you downloaded earlier. From the applications folder, import String Passing Demo into Eclipse. From the firmware folder, import String Passing Demo into MPLAB X. Connect your Android device to your computer and write the program onto the device by pressing the green play button. In MPLAB X, build the firmware and write the .hex file onto the PIC.
Start the String Passing Demo on your Android device. Then turn on the PIC and connect it. If you see "Hello from PIC32!" on your Android device, congratulations!
Firmware
The firmware consists of initialization code and a while loop with a state machine. When the phone is connected to the PIC, the state is STATE_CONNECTED. The code under the STATE_CONNECTED case transmits a string to the Android device if the user button has been pressed or released. When data is received, the function ADBCallback is called. The ADBCallback for the String Passing Demo displays any bytes received as a string on the LCD.
Application
The main parts of the application code are StringPassing.java inside src/lims.stringpassing.app and main.xml inside res/layout. There's also code that manages the connection inside src/lims.stringpassing.server.
StringPassing.java starts with the declaration of several variables: Buttons, TextViews, etc. Inside onCreate, these variables are linked to parts of the layout in main.xml. Most of the code describes listeners - basically, code that is executed in response to an event like a button press or when data is received.
Android Sensor Demo
This code contains demonstrations of four Android sensors: the GPS/location service, the camera, the touchscreen, and the microphone.
GPS demo
The location demonstration will try to determine the device's current location. It will transmit the coordinates to the PIC and the PIC will return the location directly across the world (the antipode). For Chicago, this is southwest of Australia in the ocean.
Camera demo
The camera demo captures a 640 by 480 image. It saves the image as a .jpeg, then creates a 64 by 48 pixel version and sends that to the PIC. The PIC inverts the RGB data and sends the sample back.
Touchscreen demo
The touchscreen demonstration detects where you've touched the screen and indicates this with the purple cursor. It scales the touch location to a float between 0 and 1 (for both axes) and sends this pair of floats to the PIC. Every time the PIC receives data, it responds with coordinates for the orange cursor, which it moves around (pseudo)randomly.
Microphone demo
The microphone demo captures data from the Android device's microphone but doesn't do much with it. The level bar in the application shows the maximum amplitude found in the previous sample. It sends up to 100 bytes of each sample to the PIC, which comments on the loudness.
Basics of Android programming
An Activity is a basic part of an Android application. There's an Activity for each screen in an app. The String Passing Demo is an application that consists of a single Activity because there's only one screen. The Android Sensor Demo has one Activity for the menu and four Activities for the four sensor demos. To create your own activity, you create a subclass of Android's Activity class, like public class StringPassing extends Activity.
Inside the Activity class, there are functions that are called at different parts of the Activity's life (for a diagram, see Activity Lifecycle in the documentation). When the Activity is started by the user, a method called onCreate is called. When the user closes the Activity by pressing the back button, the onDestroy method is called. For example, here's some code from the String Passing Demo:
@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); ...
The @Override designation means we're overriding the base Activity class's onCreate function. For things to work properly, the superclass's onCreate function still needs to be called; that's what super.onCreate(savedInstanceState) does. The savedInstanceState is a structure in which you can save variables. We're not going to worry about it. The final line, setContentView(R.layout.main), tells Android that the application should display the main.xml layout. The rest of onCreate is code that we want to execute at the start of the Activity.
An application's layout files are found in res/layouts in the Eclipse Package Explorer. A layout file is an xml file describing how text fields, buttons, checkboxes, and other widgets will be laid out on the screen. Eclipse gives you a friendly drag-and-drop interface with which to create these.
Of course, we need to connect the layout widgets to our application code so we can control their functionality. In the String Passing Demo, you'll see
public class StringPassing extends Activity { Button sendButton; Button clearButton; ...
and later, in the onCreate function,
sendButton = (Button) findViewById(R.id.button1); clearButton = (Button) findViewById(R.id.button2); ...
Now that we've associated the buttons in the layout with variables like sendButton and clearButton, we can call sendButton.setOnClickListener to execute certain code when sendButton is pressed by the user. unctionality. In the String Passing Demo, you'll see
public class StringPassing extends Activity { Button sendButton; Button clearButton; ...
and later, in the onCreate function,
sendButton = (Button) findViewById(R.id.button1); clearButton = (Button) findViewById(R.id.button2); ...
Now that we've associated the buttons in the layout with variables like sendButton and clearButton, we can call sendButton.setOnClickListener to execute certain code when sendButton is pressed by the user.
To learn more, see the official documentation.
Communication overview
Here's a little bit about how we're transferring data.
We're using the Android Debug Bridge (ADB) to transfer data. ADB is a tool that's usually used for development of Android applications. Google has released the Open Accessory protocol for communication with Android USB accessories, but it's only guaranteed to be supported on devices running Android 3.1 or above, where ADB is compatible with devices running Android 1.6 or above.
In this code, the Android device acts as a TCP server. On the PIC side, we're able to abuse ADB to send arbitrary sequences of bytes between an Android devices and a PIC32. On the Android side, we've used TCP server libraries to accept incoming connections from PICs. All of this runs on top of Microchip USB libraries and Linux USB drivers.
Credits
The firmware uses Ytai Ben-Tsvi's libadb, libbtstack, libconn, and libusb libraries from the ioio project. The application code uses server libraries from microbridge.