<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://hades.mech.northwestern.edu//api.php?action=feedcontributions&amp;feedformat=atom&amp;user=AndrewKessler</id>
	<title>Mech - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://hades.mech.northwestern.edu//api.php?action=feedcontributions&amp;feedformat=atom&amp;user=AndrewKessler"/>
	<link rel="alternate" type="text/html" href="https://hades.mech.northwestern.edu//index.php/Special:Contributions/AndrewKessler"/>
	<updated>2026-04-21T00:01:04Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.35.9</generator>
	<entry>
		<id>https://hades.mech.northwestern.edu//index.php?title=NU32:_VC0706_Serial_Camera&amp;diff=21463</id>
		<title>NU32: VC0706 Serial Camera</title>
		<link rel="alternate" type="text/html" href="https://hades.mech.northwestern.edu//index.php?title=NU32:_VC0706_Serial_Camera&amp;diff=21463"/>
		<updated>2012-07-14T20:48:46Z</updated>

		<summary type="html">&lt;p&gt;AndrewKessler: /* After you have a picture */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
&lt;br /&gt;
=Using the VC0706 Serial Camera Module=&lt;br /&gt;
&lt;br /&gt;
The VC0706 is a video module originally designed for surveillance purposes. It can be used to stream analog NTSC video to a monitor, or to take a snapshot and spit it out as a JPEG over a serial connection. It also has built in motion detection features. The camera can take pictures at 640x480, 320x240, or 160x200. Since using the module to stream video over an RCA connection is trivial, this tutorial will focus on retrieving snapshots.&lt;br /&gt;
&lt;br /&gt;
Since the VC0706 is its own self-contained serial module, you could just connect the camera directly to a PC using an RS232 cable, and interact with it using some terminal software. A Python script is available to directly interface with the camera over serial. The VC0706 uses 3.3V TTL logic, so if you use a 5V RS232-USB cable, make sure you step down the voltage coming out of the computer using a voltage divider, to avoid frying the camera.&lt;br /&gt;
This tutorial focuses on how to interact with the module from the perspective of a PIC32 microcontroller.&lt;br /&gt;
&lt;br /&gt;
==Wiring==&lt;br /&gt;
Simply connect the TX and RX pins on the VC0706 to any UART port on the NU32. I used UART2, which uses pins F4 and F5. Make sure you connect the camera’s TX to the PIC’s RX, and visa versa1. Also, connect VCC to 5V and GND to the PIC’s GND.&lt;br /&gt;
&lt;br /&gt;
==Open a UART port==&lt;br /&gt;
&lt;br /&gt;
The default baud is 38400. You can change the default baud rate in code once you have established communication. &lt;br /&gt;
&lt;br /&gt;
==Taking a picture==&lt;br /&gt;
The basic flow of events is as follows: freeze the image buffer on the VC0706, transfer data from VC0706 to PIC, thaw image buffer, repeat.&lt;br /&gt;
&lt;br /&gt;
If you don’t thaw the buffer after freezing it, freezing the buffer and transferring data from the buffer will just keep giving you the same picture!&lt;br /&gt;
&lt;br /&gt;
==After you have a picture==&lt;br /&gt;
After the picture is on the PIC in some kind of buffer, you can do whatever you want with it. Write it to an SD card, spit it out over serial, whatever (if you choose this route, set your terminal app to record serial output to a text file, then just rename it as a .jpg).&lt;br /&gt;
Unfortunately, this camera is not well suited for doing image processing onboard the PIC. The camera exports pictures as compressed JPEGs, meaning that the color values of each pixel (which you would want access to to analyze the image) are heavily compressed and encrypted. It is possible to decompress the JPEG to a bitmap, but the trouble is finding code to do that efficiently on an embedded platform. It would also probably be a time-consuming procedure onboard the PIC, meaning it would be difficult to use it for any sort of real-time application. But you’re welcome to try!&lt;br /&gt;
&lt;br /&gt;
==Issues==&lt;br /&gt;
Make sure you handle incoming serial transmissions from the VC0706 in an interrupt with a very large incoming buffer, because the built in UART buffer (about 8 bytes) will quickly be overwhelmed from the camera if you’re polling instead.&lt;br /&gt;
You can always make sure your camera is working by hooking it up directly to the PC using an RS232 cable, and using a Windows utility to interact with it.&lt;/div&gt;</summary>
		<author><name>AndrewKessler</name></author>
	</entry>
	<entry>
		<id>https://hades.mech.northwestern.edu//index.php?title=Microchip_PICs&amp;diff=21462</id>
		<title>Microchip PICs</title>
		<link rel="alternate" type="text/html" href="https://hades.mech.northwestern.edu//index.php?title=Microchip_PICs&amp;diff=21462"/>
		<updated>2012-07-14T20:47:54Z</updated>

		<summary type="html">&lt;p&gt;AndrewKessler: /* Using the NU32 (Winter 2012 and on) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;#039;&amp;#039;&amp;#039;Note:  Some of the code on the bottom of this page was written using the CCS compiler.  All new code is being written using Microchip&amp;#039;s MPLAB X.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;[http://peshkin.mech.northwestern.edu/pic/code Link to all PIC18F sample code here.]&amp;lt;/b&amp;gt;&lt;br /&gt;
*[[Sample code for most PIC18F4520 operations]]&lt;br /&gt;
*[http://www.ccsinfo.com/forum/ CCS user forum]&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
__TOC__&lt;br /&gt;
== The NUScope ==&lt;br /&gt;
*[[NUScope]]&lt;br /&gt;
== Using the NU32 (Winter 2012 and on) ==&lt;br /&gt;
*[[NU32: Introduction to the PIC32]]&lt;br /&gt;
**[[NU32: What is in the NU32 Kit]]&lt;br /&gt;
**[[NU32: Software to Install]]&lt;br /&gt;
**[[NU32: Starting a New Project and Putting it on the NU32]]&lt;br /&gt;
**[[NU32: A Detailed Look at Programming the PIC32 on the NU32]]&lt;br /&gt;
* Sample Code&lt;br /&gt;
**[[NU32: Serial Communication with the PC]]&lt;br /&gt;
**[[NU32: 16x2 LCD]]&lt;br /&gt;
**[[NU32: Digital Input and Output]]&lt;br /&gt;
**[[NU32: Counters and Timers]]&lt;br /&gt;
**[[NU32: Interrupts]]&lt;br /&gt;
**[[NU32: Output Compare, PWM, and Analog Output]]&lt;br /&gt;
**[[NU32: Analog Input]]&lt;br /&gt;
**[[NU32: Using the dsPIC33FJ12MC201 QEI to SPI board]]&lt;br /&gt;
**[[NU32: Using the MAX9918 current sensor]]&lt;br /&gt;
**[[NU32: Using the TB6612 H-Bridge]]&lt;br /&gt;
**[[NU32: Driving RC servo motors]]&lt;br /&gt;
**[[NU32: Driving a stepper motor]]&lt;br /&gt;
**[[NU32: Using the LS7183 Quadrature Clock Converter]]&lt;br /&gt;
**[[NU32: Using the L293D H-Bridge]]&lt;br /&gt;
**[[NU32: Digital Signal Processing]]&lt;br /&gt;
**[[NU32: Input Capture]]&lt;br /&gt;
**[[NU32: Flash Self-Programming]]&lt;br /&gt;
**[[NU32: UART Asynchronous Serial Communication]]&lt;br /&gt;
**[[NU32: I2C Synchronous Serial Communication]]&lt;br /&gt;
**[[NU32: SPI Synchronous Serial Communication]]&lt;br /&gt;
**[[NU32: Watchdog Timer]]&lt;br /&gt;
**[[NU32: VC0706 Serial Camera]]&lt;br /&gt;
**[[NU32: Using the MCP42X1 SPI Digital Potentiometer]]&lt;br /&gt;
&lt;br /&gt;
== Using the NU32v2 (Winter 2011) ==&lt;br /&gt;
*[[NU32v2: Introduction to the PIC32]]&lt;br /&gt;
**[[NU32v2: What is in the NU32v2 Kit]]&lt;br /&gt;
**[[NU32v2: Software to Install]]&lt;br /&gt;
**[[NU32v2: Starting a New Project and Putting it on the NU32v2]]&lt;br /&gt;
**[[NU32v2: Using the Simulator]]&lt;br /&gt;
**[[NU32v2: A Detailed Look at Programming the PIC32]]&lt;br /&gt;
**[[NU32v2: Benchmark Test]]&lt;br /&gt;
* Sample Code&lt;br /&gt;
**[[NU32v2: Digital Input and Output]]&lt;br /&gt;
**[[NU32v2: Counters and Timers]]&lt;br /&gt;
**[[NU32v2: Interrupts]]&lt;br /&gt;
**[[NU32v2: Output Compare, PWM, and Analog Output]]&lt;br /&gt;
**[[NU32v2: Serial Communication with the PC]]&lt;br /&gt;
**[[NU32v2: Nokia 5110 LCD]]&lt;br /&gt;
**[[NU32v2: Analog Input]]&lt;br /&gt;
**[[NU32v2: Using the LS7183 Quadrature Clock Converter]]&lt;br /&gt;
**[[NU32v2: Using the L293D H-Bridge]]&lt;br /&gt;
**[[NU32v2: Input Capture]]&lt;br /&gt;
**[[NU32v2: Flash Self-Programming]]&lt;br /&gt;
**[[NU32v2: UART Asynchronous Serial Communication]]&lt;br /&gt;
**[[NU32v2: I2C Synchronous Serial Communication]]&lt;br /&gt;
**[[NU32v2: SPI Synchronous Serial Communication]]&lt;br /&gt;
**[[NU32v2: Digital Signal Processing]]&lt;br /&gt;
**[[NU32v2: Watchdog Timer]]&lt;br /&gt;
**[[NU32v2: Simple Analog Input]]&lt;br /&gt;
&lt;br /&gt;
== Using the PIC18F4520 ==&lt;br /&gt;
*[[4520 Board intro]]&lt;br /&gt;
*[[4520 Board construction]]&lt;br /&gt;
*[[4520 Board use]]&lt;br /&gt;
*[[Microcontroller PIC18F4520]]&lt;br /&gt;
*[[PIC MCUs: Capabilities of PIC18F4520]]&lt;br /&gt;
**[[PIC18F4520: PWM Motor Control]]&lt;br /&gt;
**[[PIC18F4520: Digital Outputs]]&lt;br /&gt;
**[[PIC18F4520: Digital Inputs]]&lt;br /&gt;
**[[PIC18F4520: Serial Digital-to-Analog Conversion]]&lt;br /&gt;
**[[PIC18F4520: Analog Inputs]]&lt;br /&gt;
**[[PIC18F4520: Timers]]&lt;br /&gt;
**[[PIC18F4520: Comparator]]&lt;br /&gt;
&lt;br /&gt;
== Example Code in C for PIC18F4520==&lt;br /&gt;
*[[C Example: Parallel Interfacing with LCDs]]&lt;br /&gt;
*[[C Example: Digital Inputs]]&lt;br /&gt;
*[[C Example: PWM Motor Control]]&lt;br /&gt;
*[[C Example: Comparators]]&lt;br /&gt;
*[[C Example: Digital Outputs]]&lt;br /&gt;
*[[C Example: Analog Inputs]]&lt;br /&gt;
*[[C Example: Digital Outputs (Ports)]]&lt;br /&gt;
*[[C Example: Bi-Directional PWM Motor Control]]&lt;br /&gt;
*[[C Example: Serial LCD]]&lt;br /&gt;
&lt;br /&gt;
== Using the PIC32MX Series ==&lt;br /&gt;
*[[Introduction to the PIC32]]&lt;br /&gt;
*[[Getting Started with PIC32]] (includes NU32 development board)&lt;br /&gt;
** Download PIC32 Tutorial Files [[Media: PIC32_TutorialFiles.zip|here]].&lt;br /&gt;
** [[ME 333 Lab 2]] - Includes Digital IO, Analog Input, Parallel LCD and RS232 Com&lt;br /&gt;
** [[ME 333 Lab 4]] - Includes PWM and Encoder Motor Control&lt;br /&gt;
*[[Microcontroller PIC32MX460F512L]]&lt;br /&gt;
*[[Programming HID Bootloader on PIC32]] &lt;br /&gt;
*[[HelloWorld PIC32|Directions to code HelloWorld]]&lt;br /&gt;
*[[Directions to Load Files to PIC32 with HID Bootloader]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*[[PIC MCUs: Capabilities of PIC32MX]]&lt;br /&gt;
**[[Programming HID Bootloader on PIC32 |PIC32MX: Bootloader]]&lt;br /&gt;
**Simple Programs&lt;br /&gt;
***[[PIC32MX: Digital Inputs]]&lt;br /&gt;
***[[PIC32MX: Digital Outputs]]&lt;br /&gt;
***[[PIC32MX: Analog Inputs]]&lt;br /&gt;
**Communication&lt;br /&gt;
***[[PIC32MX: Parallel LCD]]&lt;br /&gt;
***[[PIC32MX: RS232]]&lt;br /&gt;
***[[PIC32MX:  USB Communication with a PC]]&lt;br /&gt;
***[[PIC32MX:  SPI External RAM]]&lt;br /&gt;
***[[PIC32MX:  I2C DAC]]&lt;br /&gt;
***[[PIC32MX:  I2C EEPROM]]&lt;br /&gt;
***[[PIC32MX:  SPI EEPROM]]&lt;br /&gt;
***[[PIC32MX:  I2C Communication between PIC32s]]&lt;br /&gt;
***[[PIC32MX:  SPI Communication between PIC32s]]&lt;br /&gt;
**Motor Control&lt;br /&gt;
***[[PIC32MX: PWM Motor Control|PIC32MX: PWM Motor Control]]&lt;br /&gt;
***[[PIC32MX: Encoder Motor Control|PIC32MX: Encoder Motor Control]]&lt;br /&gt;
***[[PIC32MX: Servo Control|PIC32MX: Servo Control]]&lt;br /&gt;
***[[PIC32MX:  Driving a Stepper Motor]]&lt;br /&gt;
***[[Using the LS7166 Quadrature Counter]]&lt;br /&gt;
***[[Using the LS7366R SPI Quadrature Counter]]&lt;br /&gt;
**Capabilities&lt;br /&gt;
***[[PIC32MX:  Benchmarking Mathematical Operations]]&lt;br /&gt;
***[[PIC32MX:  FFT of Analog Input]]&lt;br /&gt;
***[[PIC32MX:  Sinusoidal Analog Output]]&lt;br /&gt;
***[[PIC32MX:  XBee Wireless Round-trip Latency]]&lt;br /&gt;
***[[PIC32MX:  Interfacing with Force Sensors from a Scale]]&lt;br /&gt;
***[[PIC32MX:  Storing Data in Flash Memory (Run-Time Self Programming)]]&lt;br /&gt;
&lt;br /&gt;
==Other PIC Resources ==&lt;br /&gt;
&lt;br /&gt;
*[[PIC PWM Motor Driver]]&lt;br /&gt;
*[[Writing Code with the C18 Compiler]]&lt;br /&gt;
*[[Controlling a seven segment display]]&lt;br /&gt;
*[[PIC Microcontrollers with C18 Compiler]]&lt;br /&gt;
*[[PIC Motor Control and Serial Port Example]]&lt;br /&gt;
*[[PIC16F684]]&lt;br /&gt;
*[[PIC Microcontrollers with CCS Compiler]]&lt;br /&gt;
*[[Stepper motor control with the PIC]]&lt;br /&gt;
*[[PIC/C18 Compiler Tips and Troubleshooting]]&lt;br /&gt;
*[[CCS C]]&lt;br /&gt;
*[[Analog Input]]&lt;br /&gt;
*[[PIC MCUs: Hardware and Connections]]&lt;br /&gt;
*[[Storing constant data in program memory]]&lt;br /&gt;
*[[PIC Analog-Digital-Converter Example]]&lt;br /&gt;
*[[PIC Microcontroller]]&lt;br /&gt;
*[[Digital inputs &amp;amp; outputs]]&lt;br /&gt;
*[[Debugging C on a PIC]]&lt;br /&gt;
*[[Analog Output]]&lt;br /&gt;
*[[PIC MCUs: Software]]&lt;br /&gt;
*[[Interfacing to External EEPROM]]&lt;br /&gt;
*[[CCS IDE]]&lt;br /&gt;
*[[Interrupts]]&lt;br /&gt;
*[[PIC16F684 Registers]]&lt;br /&gt;
*[[Waveform Generation with AD9833]]&lt;br /&gt;
*[[Waveform Generation with AD9833, and SPI]]&lt;br /&gt;
*[[PIC computation time benchmarks]]&lt;br /&gt;
*[[PICkit 1]]&lt;br /&gt;
*[[PIC MCUs: 4520 Board]]&lt;br /&gt;
*[[More debugging tips]]&lt;br /&gt;
*[[Example Writeup: Analog Input]]&lt;br /&gt;
*[[LED Drivers]]&lt;br /&gt;
*[[Embedded Programming Tips for CCS C]]&lt;br /&gt;
*[[Wireless PIC bootloading]]&lt;br /&gt;
*[[PIC 18f4553]]&lt;br /&gt;
*[[I2C Motor Controller]]&lt;br /&gt;
*[[Driving a piezo speaker with a PIC]]&lt;br /&gt;
*[[PIC Servo Controller]]&lt;br /&gt;
*[[Watchdog timer]]&lt;br /&gt;
*[[Interfacing PIC with SPI memory]]&lt;br /&gt;
*[[Using the LS7166 Quadrature Counter]]&lt;br /&gt;
&lt;br /&gt;
==Programming the PIC with Microchip&amp;#039;s MPLAB==&lt;/div&gt;</summary>
		<author><name>AndrewKessler</name></author>
	</entry>
	<entry>
		<id>https://hades.mech.northwestern.edu//index.php?title=NU32:_Using_the_MCP42X1_SPI_Digital_Potentiometer&amp;diff=21461</id>
		<title>NU32: Using the MCP42X1 SPI Digital Potentiometer</title>
		<link rel="alternate" type="text/html" href="https://hades.mech.northwestern.edu//index.php?title=NU32:_Using_the_MCP42X1_SPI_Digital_Potentiometer&amp;diff=21461"/>
		<updated>2012-07-14T20:47:16Z</updated>

		<summary type="html">&lt;p&gt;AndrewKessler: /* Details */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
The MCP42X1 is a 7-bit dual digital potentiometer. It is available in total resistance options of 5, 10, 50 and 100 kOhm. It is controlled using SPI communication and a digital output (CS). It has two independent potentiometer channels, each with its own wiper.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
A potentiometer is useful in a variety of circumstances when a variable resistance is needed. A digital potentiometer provides a variable resistor that can be controlled from a microcontroller. Because the MCP42X1 is a 7-bit device, there are 2^7 = 128 possible resistance &amp;quot;steps&amp;quot;. By communicating with the IC over SPI, we can choose what step (and thus, resistance) the potentiometer is set at. &lt;br /&gt;
&lt;br /&gt;
[[image:mcp42x1.png|thumb|300px|MCP42X1 Pinout|right]]&lt;br /&gt;
&lt;br /&gt;
The resistance across the PxB and PxW (the wiper) is governed by&lt;br /&gt;
&amp;lt;math&amp;gt;R_{WB} = \frac{5\Omega;}{128} N&amp;lt;/math&amp;gt;&lt;br /&gt;
where the 5kOhm comes from the total resistance of the pot, depending on the model. The value N is the setting of the pot between 0 and 127. &lt;br /&gt;
&lt;br /&gt;
The pot requires four communication pins from a microcontroller: SPI CLK,  SDO, SDI, and one digital output.  The pot is powered with 3.3V. This model is a dual pot chip, meaning it has two completely independent potentiometer channels in the same IC, referred to as Pot 0 and Pot 1, respectively.&lt;br /&gt;
&lt;br /&gt;
== Details ==&lt;br /&gt;
[[Media:MCP42X1.pdf|Datasheet]]&lt;br /&gt;
&lt;br /&gt;
Example schematic when communicating with the NU32, using SPI channel 1:&lt;br /&gt;
* Pot 1-CS        -----&amp;gt;	   NU32-F3 (this can be any DIO pin you want, change code accordingly)&lt;br /&gt;
* Pot 2-SCK      -----&amp;gt;	   NU32-D10&lt;br /&gt;
* Pot 3-SDI       -----&amp;gt;	   NU32-D0&lt;br /&gt;
* Pot 4-VSS	-----&amp;gt;	   GND&lt;br /&gt;
* Pot 5-P1B	-----&amp;gt;       P1+&lt;br /&gt;
* Pot 6-P1W	-----&amp;gt;       P1-&lt;br /&gt;
* Pot 9-P0W     -----&amp;gt;       P0-&lt;br /&gt;
* Pot 10-P0B    -----&amp;gt;       P0+&lt;br /&gt;
* Pot 12 - SHDN -----&amp;gt;    3.3v (this pin is inverse-shutdown, so we keep it high)&lt;br /&gt;
* Pot 13-SDO  -----&amp;gt;       NU32-C4&lt;br /&gt;
* Pot 14-VDD  -----&amp;gt;       3.3v&lt;br /&gt;
&lt;br /&gt;
The resistance across PXB and PXW is what changes, labeled above as Px+ and Px-.&lt;br /&gt;
&lt;br /&gt;
== Library Functions ==&lt;br /&gt;
Code: [[Media:MCP42X1.h|MCP42X1.h]], [[Media:MCP42X1.c|MCP42X1.c]]&lt;br /&gt;
&lt;br /&gt;
Full example project: [[Media:MCP42X1_Example.zip|MCP42X1_Example.zip]]&lt;br /&gt;
&lt;br /&gt;
MCP42X1.c contains the following functions:&lt;br /&gt;
&lt;br /&gt;
* void SPI_initPots() : sets up SPI channel 1, and CS pin&lt;br /&gt;
* void incPot(int pot_num) : will increment wiper by one step&lt;br /&gt;
* void decPot(int pot_num) : will decrement wiper by one step&lt;br /&gt;
* int setPot(int pot_num, int wiper) : sets the given pot to specific wiper value (0 - 127), returns success boolean&lt;br /&gt;
* int readPot(int pot_num) : reads the current wiper setting from the pot, returns (0 - 127)&lt;br /&gt;
* void testPots() : runs tests of setting, incrementing, decrementing, and reading both channels to confirm pots are working properly&lt;br /&gt;
&lt;br /&gt;
== Sample Code ==&lt;br /&gt;
&lt;br /&gt;
Initialize and manipulate the pots:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
    SPI_initPots();&lt;br /&gt;
&lt;br /&gt;
    //Setting pots to zero...&lt;br /&gt;
     &lt;br /&gt;
     setPot(0,0);&lt;br /&gt;
     setPot(1,0);&lt;br /&gt;
   //both now at 0&lt;br /&gt;
&lt;br /&gt;
    //Setting pots to mid-range (64), or 1/2 the total resistance&lt;br /&gt;
   &lt;br /&gt;
     setPot(0,64);&lt;br /&gt;
     setPot(1,64); &lt;br /&gt;
   // both at 64&lt;br /&gt;
&lt;br /&gt;
    //Incrementing both&lt;br /&gt;
    incPot(0);&lt;br /&gt;
    incPot(1);&lt;br /&gt;
   // (now at 65)&lt;br /&gt;
&lt;br /&gt;
    //Incrementing both &lt;br /&gt;
    incPot(0);&lt;br /&gt;
    incPot(1);&lt;br /&gt;
   //now at 66&lt;br /&gt;
&lt;br /&gt;
    //Decrementing both&lt;br /&gt;
    decPot(0);&lt;br /&gt;
    decPot(1);&lt;br /&gt;
   //now 65 &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    //Decrementing both &lt;br /&gt;
    decPot(0);&lt;br /&gt;
    decPot(1);&lt;br /&gt;
   //now 64 &lt;br /&gt;
&lt;br /&gt;
    &lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>AndrewKessler</name></author>
	</entry>
	<entry>
		<id>https://hades.mech.northwestern.edu//index.php?title=NU32:_Using_the_MCP42X1_SPI_Digital_Potentiometer&amp;diff=21460</id>
		<title>NU32: Using the MCP42X1 SPI Digital Potentiometer</title>
		<link rel="alternate" type="text/html" href="https://hades.mech.northwestern.edu//index.php?title=NU32:_Using_the_MCP42X1_SPI_Digital_Potentiometer&amp;diff=21460"/>
		<updated>2012-07-14T20:46:35Z</updated>

		<summary type="html">&lt;p&gt;AndrewKessler: /* Details */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
The MCP42X1 is a 7-bit dual digital potentiometer. It is available in total resistance options of 5, 10, 50 and 100 kOhm. It is controlled using SPI communication and a digital output (CS). It has two independent potentiometer channels, each with its own wiper.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
A potentiometer is useful in a variety of circumstances when a variable resistance is needed. A digital potentiometer provides a variable resistor that can be controlled from a microcontroller. Because the MCP42X1 is a 7-bit device, there are 2^7 = 128 possible resistance &amp;quot;steps&amp;quot;. By communicating with the IC over SPI, we can choose what step (and thus, resistance) the potentiometer is set at. &lt;br /&gt;
&lt;br /&gt;
[[image:mcp42x1.png|thumb|300px|MCP42X1 Pinout|right]]&lt;br /&gt;
&lt;br /&gt;
The resistance across the PxB and PxW (the wiper) is governed by&lt;br /&gt;
&amp;lt;math&amp;gt;R_{WB} = \frac{5\Omega;}{128} N&amp;lt;/math&amp;gt;&lt;br /&gt;
where the 5kOhm comes from the total resistance of the pot, depending on the model. The value N is the setting of the pot between 0 and 127. &lt;br /&gt;
&lt;br /&gt;
The pot requires four communication pins from a microcontroller: SPI CLK,  SDO, SDI, and one digital output.  The pot is powered with 3.3V. This model is a dual pot chip, meaning it has two completely independent potentiometer channels in the same IC, referred to as Pot 0 and Pot 1, respectively.&lt;br /&gt;
&lt;br /&gt;
== Details ==&lt;br /&gt;
[[Media:MCP42X1.pdf|Datasheet]]&lt;br /&gt;
&lt;br /&gt;
Example schematic when communicating with the NU32, using SPI channel 1:&lt;br /&gt;
* Pot 1-CS        -----&amp;gt;	   F3 (this can be any DIO pin you want, change code accordingly)&lt;br /&gt;
* Pot 2-SCK      -----&amp;gt;	   D10&lt;br /&gt;
* Pot 3-SDI       -----&amp;gt;	   D0&lt;br /&gt;
* Pot 4-VSS	-----&amp;gt;	   GND&lt;br /&gt;
* Pot 5-P1B	-----&amp;gt;       P1+&lt;br /&gt;
* Pot 6-P1W	-----&amp;gt;       P1-&lt;br /&gt;
* Pot 9-P0W     -----&amp;gt;       P0-&lt;br /&gt;
* Pot 10-P0B    -----&amp;gt;       P0+&lt;br /&gt;
* Pot 12 - SHDN -----&amp;gt;    3.3v (this pin is inverse-shutdown, so we keep it high)&lt;br /&gt;
* Pot 13-SDO  -----&amp;gt;       C4&lt;br /&gt;
* Pot 14-VDD  -----&amp;gt;       3.3v&lt;br /&gt;
&lt;br /&gt;
The resistance across PXB and PXW is what changes, labeled above as Px+ and Px-.&lt;br /&gt;
&lt;br /&gt;
== Library Functions ==&lt;br /&gt;
Code: [[Media:MCP42X1.h|MCP42X1.h]], [[Media:MCP42X1.c|MCP42X1.c]]&lt;br /&gt;
&lt;br /&gt;
Full example project: [[Media:MCP42X1_Example.zip|MCP42X1_Example.zip]]&lt;br /&gt;
&lt;br /&gt;
MCP42X1.c contains the following functions:&lt;br /&gt;
&lt;br /&gt;
* void SPI_initPots() : sets up SPI channel 1, and CS pin&lt;br /&gt;
* void incPot(int pot_num) : will increment wiper by one step&lt;br /&gt;
* void decPot(int pot_num) : will decrement wiper by one step&lt;br /&gt;
* int setPot(int pot_num, int wiper) : sets the given pot to specific wiper value (0 - 127), returns success boolean&lt;br /&gt;
* int readPot(int pot_num) : reads the current wiper setting from the pot, returns (0 - 127)&lt;br /&gt;
* void testPots() : runs tests of setting, incrementing, decrementing, and reading both channels to confirm pots are working properly&lt;br /&gt;
&lt;br /&gt;
== Sample Code ==&lt;br /&gt;
&lt;br /&gt;
Initialize and manipulate the pots:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
    SPI_initPots();&lt;br /&gt;
&lt;br /&gt;
    //Setting pots to zero...&lt;br /&gt;
     &lt;br /&gt;
     setPot(0,0);&lt;br /&gt;
     setPot(1,0);&lt;br /&gt;
   //both now at 0&lt;br /&gt;
&lt;br /&gt;
    //Setting pots to mid-range (64), or 1/2 the total resistance&lt;br /&gt;
   &lt;br /&gt;
     setPot(0,64);&lt;br /&gt;
     setPot(1,64); &lt;br /&gt;
   // both at 64&lt;br /&gt;
&lt;br /&gt;
    //Incrementing both&lt;br /&gt;
    incPot(0);&lt;br /&gt;
    incPot(1);&lt;br /&gt;
   // (now at 65)&lt;br /&gt;
&lt;br /&gt;
    //Incrementing both &lt;br /&gt;
    incPot(0);&lt;br /&gt;
    incPot(1);&lt;br /&gt;
   //now at 66&lt;br /&gt;
&lt;br /&gt;
    //Decrementing both&lt;br /&gt;
    decPot(0);&lt;br /&gt;
    decPot(1);&lt;br /&gt;
   //now 65 &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    //Decrementing both &lt;br /&gt;
    decPot(0);&lt;br /&gt;
    decPot(1);&lt;br /&gt;
   //now 64 &lt;br /&gt;
&lt;br /&gt;
    &lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>AndrewKessler</name></author>
	</entry>
	<entry>
		<id>https://hades.mech.northwestern.edu//index.php?title=NU32:_Using_the_MCP42X1_SPI_Digital_Potentiometer&amp;diff=21459</id>
		<title>NU32: Using the MCP42X1 SPI Digital Potentiometer</title>
		<link rel="alternate" type="text/html" href="https://hades.mech.northwestern.edu//index.php?title=NU32:_Using_the_MCP42X1_SPI_Digital_Potentiometer&amp;diff=21459"/>
		<updated>2012-07-14T18:19:11Z</updated>

		<summary type="html">&lt;p&gt;AndrewKessler: /* Sample Code */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
The MCP42X1 is a 7-bit dual digital potentiometer. It is available in total resistance options of 5, 10, 50 and 100 kOhm. It is controlled using SPI communication and a digital output (CS). It has two independent potentiometer channels, each with its own wiper.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
A potentiometer is useful in a variety of circumstances when a variable resistance is needed. A digital potentiometer provides a variable resistor that can be controlled from a microcontroller. Because the MCP42X1 is a 7-bit device, there are 2^7 = 128 possible resistance &amp;quot;steps&amp;quot;. By communicating with the IC over SPI, we can choose what step (and thus, resistance) the potentiometer is set at. &lt;br /&gt;
&lt;br /&gt;
[[image:mcp42x1.png|thumb|300px|MCP42X1 Pinout|right]]&lt;br /&gt;
&lt;br /&gt;
The resistance across the PxB and PxW (the wiper) is governed by&lt;br /&gt;
&amp;lt;math&amp;gt;R_{WB} = \frac{5\Omega;}{128} N&amp;lt;/math&amp;gt;&lt;br /&gt;
where the 5kOhm comes from the total resistance of the pot, depending on the model. The value N is the setting of the pot between 0 and 127. &lt;br /&gt;
&lt;br /&gt;
The pot requires four communication pins from a microcontroller: SPI CLK,  SDO, SDI, and one digital output.  The pot is powered with 3.3V. This model is a dual pot chip, meaning it has two completely independent potentiometer channels in the same IC, referred to as Pot 0 and Pot 1, respectively.&lt;br /&gt;
&lt;br /&gt;
== Details ==&lt;br /&gt;
[[Media:MCP42X1.pdf|Datasheet]]&lt;br /&gt;
&lt;br /&gt;
Example schematic when communicating with the NU32, using SPI channel 1:&lt;br /&gt;
* Pot 1-CS        -----&amp;gt;	   F3&lt;br /&gt;
* Pot 2-SCK      -----&amp;gt;	   D10&lt;br /&gt;
* Pot 3-SDI       -----&amp;gt;	   D0&lt;br /&gt;
* Pot 4-VSS	-----&amp;gt;	   GND&lt;br /&gt;
* Pot 5-P1B	-----&amp;gt;       P1+&lt;br /&gt;
* Pot 6-P1W	-----&amp;gt;       P1-&lt;br /&gt;
* Pot 9-P0W     -----&amp;gt;       P0-&lt;br /&gt;
* Pot 10-P0B    -----&amp;gt;       P0+&lt;br /&gt;
* Pot 12 - SHDN -----&amp;gt;    3.3v (this pin is inverse-shutdown, so we keep it high)&lt;br /&gt;
* Pot 13-SDO  -----&amp;gt;       C4&lt;br /&gt;
* Pot 14-VDD  -----&amp;gt;       3.3v&lt;br /&gt;
&lt;br /&gt;
The resistance across PXB and PXW is what changes, labeled above as Px+ and Px-.&lt;br /&gt;
&lt;br /&gt;
== Library Functions ==&lt;br /&gt;
Code: [[Media:MCP42X1.h|MCP42X1.h]], [[Media:MCP42X1.c|MCP42X1.c]]&lt;br /&gt;
&lt;br /&gt;
Full example project: [[Media:MCP42X1_Example.zip|MCP42X1_Example.zip]]&lt;br /&gt;
&lt;br /&gt;
MCP42X1.c contains the following functions:&lt;br /&gt;
&lt;br /&gt;
* void SPI_initPots() : sets up SPI channel 1, and CS pin&lt;br /&gt;
* void incPot(int pot_num) : will increment wiper by one step&lt;br /&gt;
* void decPot(int pot_num) : will decrement wiper by one step&lt;br /&gt;
* int setPot(int pot_num, int wiper) : sets the given pot to specific wiper value (0 - 127), returns success boolean&lt;br /&gt;
* int readPot(int pot_num) : reads the current wiper setting from the pot, returns (0 - 127)&lt;br /&gt;
* void testPots() : runs tests of setting, incrementing, decrementing, and reading both channels to confirm pots are working properly&lt;br /&gt;
&lt;br /&gt;
== Sample Code ==&lt;br /&gt;
&lt;br /&gt;
Initialize and manipulate the pots:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
    SPI_initPots();&lt;br /&gt;
&lt;br /&gt;
    //Setting pots to zero...&lt;br /&gt;
     &lt;br /&gt;
     setPot(0,0);&lt;br /&gt;
     setPot(1,0);&lt;br /&gt;
   //both now at 0&lt;br /&gt;
&lt;br /&gt;
    //Setting pots to mid-range (64), or 1/2 the total resistance&lt;br /&gt;
   &lt;br /&gt;
     setPot(0,64);&lt;br /&gt;
     setPot(1,64); &lt;br /&gt;
   // both at 64&lt;br /&gt;
&lt;br /&gt;
    //Incrementing both&lt;br /&gt;
    incPot(0);&lt;br /&gt;
    incPot(1);&lt;br /&gt;
   // (now at 65)&lt;br /&gt;
&lt;br /&gt;
    //Incrementing both &lt;br /&gt;
    incPot(0);&lt;br /&gt;
    incPot(1);&lt;br /&gt;
   //now at 66&lt;br /&gt;
&lt;br /&gt;
    //Decrementing both&lt;br /&gt;
    decPot(0);&lt;br /&gt;
    decPot(1);&lt;br /&gt;
   //now 65 &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    //Decrementing both &lt;br /&gt;
    decPot(0);&lt;br /&gt;
    decPot(1);&lt;br /&gt;
   //now 64 &lt;br /&gt;
&lt;br /&gt;
    &lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>AndrewKessler</name></author>
	</entry>
	<entry>
		<id>https://hades.mech.northwestern.edu//index.php?title=NU32:_Using_the_MCP42X1_SPI_Digital_Potentiometer&amp;diff=21458</id>
		<title>NU32: Using the MCP42X1 SPI Digital Potentiometer</title>
		<link rel="alternate" type="text/html" href="https://hades.mech.northwestern.edu//index.php?title=NU32:_Using_the_MCP42X1_SPI_Digital_Potentiometer&amp;diff=21458"/>
		<updated>2012-07-14T18:18:18Z</updated>

		<summary type="html">&lt;p&gt;AndrewKessler: /* Details */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
The MCP42X1 is a 7-bit dual digital potentiometer. It is available in total resistance options of 5, 10, 50 and 100 kOhm. It is controlled using SPI communication and a digital output (CS). It has two independent potentiometer channels, each with its own wiper.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
A potentiometer is useful in a variety of circumstances when a variable resistance is needed. A digital potentiometer provides a variable resistor that can be controlled from a microcontroller. Because the MCP42X1 is a 7-bit device, there are 2^7 = 128 possible resistance &amp;quot;steps&amp;quot;. By communicating with the IC over SPI, we can choose what step (and thus, resistance) the potentiometer is set at. &lt;br /&gt;
&lt;br /&gt;
[[image:mcp42x1.png|thumb|300px|MCP42X1 Pinout|right]]&lt;br /&gt;
&lt;br /&gt;
The resistance across the PxB and PxW (the wiper) is governed by&lt;br /&gt;
&amp;lt;math&amp;gt;R_{WB} = \frac{5\Omega;}{128} N&amp;lt;/math&amp;gt;&lt;br /&gt;
where the 5kOhm comes from the total resistance of the pot, depending on the model. The value N is the setting of the pot between 0 and 127. &lt;br /&gt;
&lt;br /&gt;
The pot requires four communication pins from a microcontroller: SPI CLK,  SDO, SDI, and one digital output.  The pot is powered with 3.3V. This model is a dual pot chip, meaning it has two completely independent potentiometer channels in the same IC, referred to as Pot 0 and Pot 1, respectively.&lt;br /&gt;
&lt;br /&gt;
== Details ==&lt;br /&gt;
[[Media:MCP42X1.pdf|Datasheet]]&lt;br /&gt;
&lt;br /&gt;
Example schematic when communicating with the NU32, using SPI channel 1:&lt;br /&gt;
* Pot 1-CS        -----&amp;gt;	   F3&lt;br /&gt;
* Pot 2-SCK      -----&amp;gt;	   D10&lt;br /&gt;
* Pot 3-SDI       -----&amp;gt;	   D0&lt;br /&gt;
* Pot 4-VSS	-----&amp;gt;	   GND&lt;br /&gt;
* Pot 5-P1B	-----&amp;gt;       P1+&lt;br /&gt;
* Pot 6-P1W	-----&amp;gt;       P1-&lt;br /&gt;
* Pot 9-P0W     -----&amp;gt;       P0-&lt;br /&gt;
* Pot 10-P0B    -----&amp;gt;       P0+&lt;br /&gt;
* Pot 12 - SHDN -----&amp;gt;    3.3v (this pin is inverse-shutdown, so we keep it high)&lt;br /&gt;
* Pot 13-SDO  -----&amp;gt;       C4&lt;br /&gt;
* Pot 14-VDD  -----&amp;gt;       3.3v&lt;br /&gt;
&lt;br /&gt;
The resistance across PXB and PXW is what changes, labeled above as Px+ and Px-.&lt;br /&gt;
&lt;br /&gt;
== Library Functions ==&lt;br /&gt;
Code: [[Media:MCP42X1.h|MCP42X1.h]], [[Media:MCP42X1.c|MCP42X1.c]]&lt;br /&gt;
&lt;br /&gt;
Full example project: [[Media:MCP42X1_Example.zip|MCP42X1_Example.zip]]&lt;br /&gt;
&lt;br /&gt;
MCP42X1.c contains the following functions:&lt;br /&gt;
&lt;br /&gt;
* void SPI_initPots() : sets up SPI channel 1, and CS pin&lt;br /&gt;
* void incPot(int pot_num) : will increment wiper by one step&lt;br /&gt;
* void decPot(int pot_num) : will decrement wiper by one step&lt;br /&gt;
* int setPot(int pot_num, int wiper) : sets the given pot to specific wiper value (0 - 127), returns success boolean&lt;br /&gt;
* int readPot(int pot_num) : reads the current wiper setting from the pot, returns (0 - 127)&lt;br /&gt;
* void testPots() : runs tests of setting, incrementing, decrementing, and reading both channels to confirm pots are working properly&lt;br /&gt;
&lt;br /&gt;
== Sample Code ==&lt;br /&gt;
&lt;br /&gt;
Initialize and clear the LCD:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
    SPI_initPots();&lt;br /&gt;
&lt;br /&gt;
    //Setting pots to zero...&lt;br /&gt;
     &lt;br /&gt;
     setPot(0,0);&lt;br /&gt;
     setPot(1,0);&lt;br /&gt;
   //both now at 0&lt;br /&gt;
&lt;br /&gt;
    //Setting pots to mid-range (64), or 1/2 the total resistance&lt;br /&gt;
   &lt;br /&gt;
     setPot(0,64);&lt;br /&gt;
     setPot(1,64); &lt;br /&gt;
   // both at 64&lt;br /&gt;
&lt;br /&gt;
    //Incrementing both&lt;br /&gt;
    incPot(0);&lt;br /&gt;
    incPot(1);&lt;br /&gt;
   // (now at 65)&lt;br /&gt;
&lt;br /&gt;
    //Incrementing both &lt;br /&gt;
    incPot(0);&lt;br /&gt;
    incPot(1);&lt;br /&gt;
   //now at 66&lt;br /&gt;
&lt;br /&gt;
    //Decrementing both&lt;br /&gt;
    decPot(0);&lt;br /&gt;
    decPot(1);&lt;br /&gt;
   //now 65 &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    //Decrementing both &lt;br /&gt;
    decPot(0);&lt;br /&gt;
    decPot(1);&lt;br /&gt;
   //now 64 &lt;br /&gt;
&lt;br /&gt;
    &lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>AndrewKessler</name></author>
	</entry>
	<entry>
		<id>https://hades.mech.northwestern.edu//index.php?title=NU32:_Using_the_MCP42X1_SPI_Digital_Potentiometer&amp;diff=21457</id>
		<title>NU32: Using the MCP42X1 SPI Digital Potentiometer</title>
		<link rel="alternate" type="text/html" href="https://hades.mech.northwestern.edu//index.php?title=NU32:_Using_the_MCP42X1_SPI_Digital_Potentiometer&amp;diff=21457"/>
		<updated>2012-07-14T18:17:35Z</updated>

		<summary type="html">&lt;p&gt;AndrewKessler: /* Sample Code */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
The MCP42X1 is a 7-bit dual digital potentiometer. It is available in total resistance options of 5, 10, 50 and 100 kOhm. It is controlled using SPI communication and a digital output (CS). It has two independent potentiometer channels, each with its own wiper.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
A potentiometer is useful in a variety of circumstances when a variable resistance is needed. A digital potentiometer provides a variable resistor that can be controlled from a microcontroller. Because the MCP42X1 is a 7-bit device, there are 2^7 = 128 possible resistance &amp;quot;steps&amp;quot;. By communicating with the IC over SPI, we can choose what step (and thus, resistance) the potentiometer is set at. &lt;br /&gt;
&lt;br /&gt;
[[image:mcp42x1.png|thumb|300px|MCP42X1 Pinout|right]]&lt;br /&gt;
&lt;br /&gt;
The resistance across the PxB and PxW (the wiper) is governed by&lt;br /&gt;
&amp;lt;math&amp;gt;R_{WB} = \frac{5\Omega;}{128} N&amp;lt;/math&amp;gt;&lt;br /&gt;
where the 5kOhm comes from the total resistance of the pot, depending on the model. The value N is the setting of the pot between 0 and 127. &lt;br /&gt;
&lt;br /&gt;
The pot requires four communication pins from a microcontroller: SPI CLK,  SDO, SDI, and one digital output.  The pot is powered with 3.3V. This model is a dual pot chip, meaning it has two completely independent potentiometer channels in the same IC, referred to as Pot 0 and Pot 1, respectively.&lt;br /&gt;
&lt;br /&gt;
== Details ==&lt;br /&gt;
[[Media:MCP42X1.pdf|Datasheet]]&lt;br /&gt;
&lt;br /&gt;
Example schematic when communicating with the NU32, using SPI channel 1:&lt;br /&gt;
* Pot 1-CS        -----&amp;gt;	   F3&lt;br /&gt;
* Pot 2-SCK      -----&amp;gt;	   D10&lt;br /&gt;
* Pot 3-SDI       -----&amp;gt;	   D0&lt;br /&gt;
* Pot 4-VSS	-----&amp;gt;	   GND&lt;br /&gt;
* Pot 5-P1B	-----&amp;gt;       P1+&lt;br /&gt;
* Pot 6-P1W	-----&amp;gt;       P1-&lt;br /&gt;
* Pot 7-P1A	-----&amp;gt;      NC&lt;br /&gt;
* Pot 8-P0A     -----&amp;gt;       NC&lt;br /&gt;
* Pot 9-P0W    -----&amp;gt;       P0-&lt;br /&gt;
* Pot 10-P0B   -----&amp;gt;       P0+&lt;br /&gt;
* Pot 11 -WP   -----&amp;gt;       NC&lt;br /&gt;
* Pot 12 - SHDN -----&amp;gt;    3.3v (this pin is inverse-shutdown, so we keep it high)&lt;br /&gt;
* Pot 13-SDO  -----&amp;gt;       C4&lt;br /&gt;
* Pot 14-VDD  -----&amp;gt;       3.3v&lt;br /&gt;
&lt;br /&gt;
The resistance across PXB and PXW is what changes, labeled above as Px+ and Px-.&lt;br /&gt;
&lt;br /&gt;
== Library Functions ==&lt;br /&gt;
Code: [[Media:MCP42X1.h|MCP42X1.h]], [[Media:MCP42X1.c|MCP42X1.c]]&lt;br /&gt;
&lt;br /&gt;
Full example project: [[Media:MCP42X1_Example.zip|MCP42X1_Example.zip]]&lt;br /&gt;
&lt;br /&gt;
MCP42X1.c contains the following functions:&lt;br /&gt;
&lt;br /&gt;
* void SPI_initPots() : sets up SPI channel 1, and CS pin&lt;br /&gt;
* void incPot(int pot_num) : will increment wiper by one step&lt;br /&gt;
* void decPot(int pot_num) : will decrement wiper by one step&lt;br /&gt;
* int setPot(int pot_num, int wiper) : sets the given pot to specific wiper value (0 - 127), returns success boolean&lt;br /&gt;
* int readPot(int pot_num) : reads the current wiper setting from the pot, returns (0 - 127)&lt;br /&gt;
* void testPots() : runs tests of setting, incrementing, decrementing, and reading both channels to confirm pots are working properly&lt;br /&gt;
&lt;br /&gt;
== Sample Code ==&lt;br /&gt;
&lt;br /&gt;
Initialize and clear the LCD:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
    SPI_initPots();&lt;br /&gt;
&lt;br /&gt;
    //Setting pots to zero...&lt;br /&gt;
     &lt;br /&gt;
     setPot(0,0);&lt;br /&gt;
     setPot(1,0);&lt;br /&gt;
   //both now at 0&lt;br /&gt;
&lt;br /&gt;
    //Setting pots to mid-range (64), or 1/2 the total resistance&lt;br /&gt;
   &lt;br /&gt;
     setPot(0,64);&lt;br /&gt;
     setPot(1,64); &lt;br /&gt;
   // both at 64&lt;br /&gt;
&lt;br /&gt;
    //Incrementing both&lt;br /&gt;
    incPot(0);&lt;br /&gt;
    incPot(1);&lt;br /&gt;
   // (now at 65)&lt;br /&gt;
&lt;br /&gt;
    //Incrementing both &lt;br /&gt;
    incPot(0);&lt;br /&gt;
    incPot(1);&lt;br /&gt;
   //now at 66&lt;br /&gt;
&lt;br /&gt;
    //Decrementing both&lt;br /&gt;
    decPot(0);&lt;br /&gt;
    decPot(1);&lt;br /&gt;
   //now 65 &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    //Decrementing both &lt;br /&gt;
    decPot(0);&lt;br /&gt;
    decPot(1);&lt;br /&gt;
   //now 64 &lt;br /&gt;
&lt;br /&gt;
    &lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>AndrewKessler</name></author>
	</entry>
	<entry>
		<id>https://hades.mech.northwestern.edu//index.php?title=NU32:_Using_the_MCP42X1_SPI_Digital_Potentiometer&amp;diff=21456</id>
		<title>NU32: Using the MCP42X1 SPI Digital Potentiometer</title>
		<link rel="alternate" type="text/html" href="https://hades.mech.northwestern.edu//index.php?title=NU32:_Using_the_MCP42X1_SPI_Digital_Potentiometer&amp;diff=21456"/>
		<updated>2012-07-14T18:17:00Z</updated>

		<summary type="html">&lt;p&gt;AndrewKessler: /* Sample Code */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
The MCP42X1 is a 7-bit dual digital potentiometer. It is available in total resistance options of 5, 10, 50 and 100 kOhm. It is controlled using SPI communication and a digital output (CS). It has two independent potentiometer channels, each with its own wiper.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
A potentiometer is useful in a variety of circumstances when a variable resistance is needed. A digital potentiometer provides a variable resistor that can be controlled from a microcontroller. Because the MCP42X1 is a 7-bit device, there are 2^7 = 128 possible resistance &amp;quot;steps&amp;quot;. By communicating with the IC over SPI, we can choose what step (and thus, resistance) the potentiometer is set at. &lt;br /&gt;
&lt;br /&gt;
[[image:mcp42x1.png|thumb|300px|MCP42X1 Pinout|right]]&lt;br /&gt;
&lt;br /&gt;
The resistance across the PxB and PxW (the wiper) is governed by&lt;br /&gt;
&amp;lt;math&amp;gt;R_{WB} = \frac{5\Omega;}{128} N&amp;lt;/math&amp;gt;&lt;br /&gt;
where the 5kOhm comes from the total resistance of the pot, depending on the model. The value N is the setting of the pot between 0 and 127. &lt;br /&gt;
&lt;br /&gt;
The pot requires four communication pins from a microcontroller: SPI CLK,  SDO, SDI, and one digital output.  The pot is powered with 3.3V. This model is a dual pot chip, meaning it has two completely independent potentiometer channels in the same IC, referred to as Pot 0 and Pot 1, respectively.&lt;br /&gt;
&lt;br /&gt;
== Details ==&lt;br /&gt;
[[Media:MCP42X1.pdf|Datasheet]]&lt;br /&gt;
&lt;br /&gt;
Example schematic when communicating with the NU32, using SPI channel 1:&lt;br /&gt;
* Pot 1-CS        -----&amp;gt;	   F3&lt;br /&gt;
* Pot 2-SCK      -----&amp;gt;	   D10&lt;br /&gt;
* Pot 3-SDI       -----&amp;gt;	   D0&lt;br /&gt;
* Pot 4-VSS	-----&amp;gt;	   GND&lt;br /&gt;
* Pot 5-P1B	-----&amp;gt;       P1+&lt;br /&gt;
* Pot 6-P1W	-----&amp;gt;       P1-&lt;br /&gt;
* Pot 7-P1A	-----&amp;gt;      NC&lt;br /&gt;
* Pot 8-P0A     -----&amp;gt;       NC&lt;br /&gt;
* Pot 9-P0W    -----&amp;gt;       P0-&lt;br /&gt;
* Pot 10-P0B   -----&amp;gt;       P0+&lt;br /&gt;
* Pot 11 -WP   -----&amp;gt;       NC&lt;br /&gt;
* Pot 12 - SHDN -----&amp;gt;    3.3v (this pin is inverse-shutdown, so we keep it high)&lt;br /&gt;
* Pot 13-SDO  -----&amp;gt;       C4&lt;br /&gt;
* Pot 14-VDD  -----&amp;gt;       3.3v&lt;br /&gt;
&lt;br /&gt;
The resistance across PXB and PXW is what changes, labeled above as Px+ and Px-.&lt;br /&gt;
&lt;br /&gt;
== Library Functions ==&lt;br /&gt;
Code: [[Media:MCP42X1.h|MCP42X1.h]], [[Media:MCP42X1.c|MCP42X1.c]]&lt;br /&gt;
&lt;br /&gt;
Full example project: [[Media:MCP42X1_Example.zip|MCP42X1_Example.zip]]&lt;br /&gt;
&lt;br /&gt;
MCP42X1.c contains the following functions:&lt;br /&gt;
&lt;br /&gt;
* void SPI_initPots() : sets up SPI channel 1, and CS pin&lt;br /&gt;
* void incPot(int pot_num) : will increment wiper by one step&lt;br /&gt;
* void decPot(int pot_num) : will decrement wiper by one step&lt;br /&gt;
* int setPot(int pot_num, int wiper) : sets the given pot to specific wiper value (0 - 127), returns success boolean&lt;br /&gt;
* int readPot(int pot_num) : reads the current wiper setting from the pot, returns (0 - 127)&lt;br /&gt;
* void testPots() : runs tests of setting, incrementing, decrementing, and reading both channels to confirm pots are working properly&lt;br /&gt;
&lt;br /&gt;
== Sample Code ==&lt;br /&gt;
&lt;br /&gt;
Initialize and clear the LCD:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
    SPI_initPots();&lt;br /&gt;
&lt;br /&gt;
    //Setting pots to zero...&lt;br /&gt;
     &lt;br /&gt;
     setPot(0,0);&lt;br /&gt;
     setPot(1,0);&lt;br /&gt;
   //both now at 0&lt;br /&gt;
&lt;br /&gt;
    //Setting pots to mid-range (64), or 5 kOhm&lt;br /&gt;
   &lt;br /&gt;
     setPot(0,64);&lt;br /&gt;
     setPot(1,64); &lt;br /&gt;
   // both at 64&lt;br /&gt;
&lt;br /&gt;
    //Incrementing both&lt;br /&gt;
    incPot(0);&lt;br /&gt;
    incPot(1);&lt;br /&gt;
   // (now at 65)&lt;br /&gt;
&lt;br /&gt;
    //Incrementing both &lt;br /&gt;
    incPot(0);&lt;br /&gt;
    incPot(1);&lt;br /&gt;
   //now at 66&lt;br /&gt;
&lt;br /&gt;
    //Decrementing both&lt;br /&gt;
    decPot(0);&lt;br /&gt;
    decPot(1);&lt;br /&gt;
   //now 65 &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    //Decrementing both &lt;br /&gt;
    decPot(0);&lt;br /&gt;
    decPot(1);&lt;br /&gt;
   //now 64 &lt;br /&gt;
&lt;br /&gt;
    &lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>AndrewKessler</name></author>
	</entry>
	<entry>
		<id>https://hades.mech.northwestern.edu//index.php?title=File:MCP42X1_Example.zip&amp;diff=21455</id>
		<title>File:MCP42X1 Example.zip</title>
		<link rel="alternate" type="text/html" href="https://hades.mech.northwestern.edu//index.php?title=File:MCP42X1_Example.zip&amp;diff=21455"/>
		<updated>2012-07-14T18:11:06Z</updated>

		<summary type="html">&lt;p&gt;AndrewKessler: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>AndrewKessler</name></author>
	</entry>
	<entry>
		<id>https://hades.mech.northwestern.edu//index.php?title=NU32:_Using_the_MCP42X1_SPI_Digital_Potentiometer&amp;diff=21454</id>
		<title>NU32: Using the MCP42X1 SPI Digital Potentiometer</title>
		<link rel="alternate" type="text/html" href="https://hades.mech.northwestern.edu//index.php?title=NU32:_Using_the_MCP42X1_SPI_Digital_Potentiometer&amp;diff=21454"/>
		<updated>2012-07-14T18:10:52Z</updated>

		<summary type="html">&lt;p&gt;AndrewKessler: /* Library Functions */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
The MCP42X1 is a 7-bit dual digital potentiometer. It is available in total resistance options of 5, 10, 50 and 100 kOhm. It is controlled using SPI communication and a digital output (CS). It has two independent potentiometer channels, each with its own wiper.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
A potentiometer is useful in a variety of circumstances when a variable resistance is needed. A digital potentiometer provides a variable resistor that can be controlled from a microcontroller. Because the MCP42X1 is a 7-bit device, there are 2^7 = 128 possible resistance &amp;quot;steps&amp;quot;. By communicating with the IC over SPI, we can choose what step (and thus, resistance) the potentiometer is set at. &lt;br /&gt;
&lt;br /&gt;
[[image:mcp42x1.png|thumb|300px|MCP42X1 Pinout|right]]&lt;br /&gt;
&lt;br /&gt;
The resistance across the PxB and PxW (the wiper) is governed by&lt;br /&gt;
&amp;lt;math&amp;gt;R_{WB} = \frac{5\Omega;}{128} N&amp;lt;/math&amp;gt;&lt;br /&gt;
where the 5kOhm comes from the total resistance of the pot, depending on the model. The value N is the setting of the pot between 0 and 127. &lt;br /&gt;
&lt;br /&gt;
The pot requires four communication pins from a microcontroller: SPI CLK,  SDO, SDI, and one digital output.  The pot is powered with 3.3V. This model is a dual pot chip, meaning it has two completely independent potentiometer channels in the same IC, referred to as Pot 0 and Pot 1, respectively.&lt;br /&gt;
&lt;br /&gt;
== Details ==&lt;br /&gt;
[[Media:MCP42X1.pdf|Datasheet]]&lt;br /&gt;
&lt;br /&gt;
Example schematic when communicating with the NU32, using SPI channel 1:&lt;br /&gt;
* Pot 1-CS        -----&amp;gt;	   F3&lt;br /&gt;
* Pot 2-SCK      -----&amp;gt;	   D10&lt;br /&gt;
* Pot 3-SDI       -----&amp;gt;	   D0&lt;br /&gt;
* Pot 4-VSS	-----&amp;gt;	   GND&lt;br /&gt;
* Pot 5-P1B	-----&amp;gt;       P1+&lt;br /&gt;
* Pot 6-P1W	-----&amp;gt;       P1-&lt;br /&gt;
* Pot 7-P1A	-----&amp;gt;      NC&lt;br /&gt;
* Pot 8-P0A     -----&amp;gt;       NC&lt;br /&gt;
* Pot 9-P0W    -----&amp;gt;       P0-&lt;br /&gt;
* Pot 10-P0B   -----&amp;gt;       P0+&lt;br /&gt;
* Pot 11 -WP   -----&amp;gt;       NC&lt;br /&gt;
* Pot 12 - SHDN -----&amp;gt;    3.3v (this pin is inverse-shutdown, so we keep it high)&lt;br /&gt;
* Pot 13-SDO  -----&amp;gt;       C4&lt;br /&gt;
* Pot 14-VDD  -----&amp;gt;       3.3v&lt;br /&gt;
&lt;br /&gt;
The resistance across PXB and PXW is what changes, labeled above as Px+ and Px-.&lt;br /&gt;
&lt;br /&gt;
== Library Functions ==&lt;br /&gt;
Code: [[Media:MCP42X1.h|MCP42X1.h]], [[Media:MCP42X1.c|MCP42X1.c]]&lt;br /&gt;
&lt;br /&gt;
Full example project: [[Media:MCP42X1_Example.zip|MCP42X1_Example.zip]]&lt;br /&gt;
&lt;br /&gt;
MCP42X1.c contains the following functions:&lt;br /&gt;
&lt;br /&gt;
* void SPI_initPots() : sets up SPI channel 1, and CS pin&lt;br /&gt;
* void incPot(int pot_num) : will increment wiper by one step&lt;br /&gt;
* void decPot(int pot_num) : will decrement wiper by one step&lt;br /&gt;
* int setPot(int pot_num, int wiper) : sets the given pot to specific wiper value (0 - 127), returns success boolean&lt;br /&gt;
* int readPot(int pot_num) : reads the current wiper setting from the pot, returns (0 - 127)&lt;br /&gt;
* void testPots() : runs tests of setting, incrementing, decrementing, and reading both channels to confirm pots are working properly&lt;br /&gt;
&lt;br /&gt;
== Sample Code ==&lt;br /&gt;
&lt;br /&gt;
Initialize and clear the LCD:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
  LcdInitialize();&lt;br /&gt;
  LcdClear();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>AndrewKessler</name></author>
	</entry>
	<entry>
		<id>https://hades.mech.northwestern.edu//index.php?title=NU32:_Using_the_MCP42X1_SPI_Digital_Potentiometer&amp;diff=21453</id>
		<title>NU32: Using the MCP42X1 SPI Digital Potentiometer</title>
		<link rel="alternate" type="text/html" href="https://hades.mech.northwestern.edu//index.php?title=NU32:_Using_the_MCP42X1_SPI_Digital_Potentiometer&amp;diff=21453"/>
		<updated>2012-07-14T18:10:30Z</updated>

		<summary type="html">&lt;p&gt;AndrewKessler: /* Library Functions */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
The MCP42X1 is a 7-bit dual digital potentiometer. It is available in total resistance options of 5, 10, 50 and 100 kOhm. It is controlled using SPI communication and a digital output (CS). It has two independent potentiometer channels, each with its own wiper.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
A potentiometer is useful in a variety of circumstances when a variable resistance is needed. A digital potentiometer provides a variable resistor that can be controlled from a microcontroller. Because the MCP42X1 is a 7-bit device, there are 2^7 = 128 possible resistance &amp;quot;steps&amp;quot;. By communicating with the IC over SPI, we can choose what step (and thus, resistance) the potentiometer is set at. &lt;br /&gt;
&lt;br /&gt;
[[image:mcp42x1.png|thumb|300px|MCP42X1 Pinout|right]]&lt;br /&gt;
&lt;br /&gt;
The resistance across the PxB and PxW (the wiper) is governed by&lt;br /&gt;
&amp;lt;math&amp;gt;R_{WB} = \frac{5\Omega;}{128} N&amp;lt;/math&amp;gt;&lt;br /&gt;
where the 5kOhm comes from the total resistance of the pot, depending on the model. The value N is the setting of the pot between 0 and 127. &lt;br /&gt;
&lt;br /&gt;
The pot requires four communication pins from a microcontroller: SPI CLK,  SDO, SDI, and one digital output.  The pot is powered with 3.3V. This model is a dual pot chip, meaning it has two completely independent potentiometer channels in the same IC, referred to as Pot 0 and Pot 1, respectively.&lt;br /&gt;
&lt;br /&gt;
== Details ==&lt;br /&gt;
[[Media:MCP42X1.pdf|Datasheet]]&lt;br /&gt;
&lt;br /&gt;
Example schematic when communicating with the NU32, using SPI channel 1:&lt;br /&gt;
* Pot 1-CS        -----&amp;gt;	   F3&lt;br /&gt;
* Pot 2-SCK      -----&amp;gt;	   D10&lt;br /&gt;
* Pot 3-SDI       -----&amp;gt;	   D0&lt;br /&gt;
* Pot 4-VSS	-----&amp;gt;	   GND&lt;br /&gt;
* Pot 5-P1B	-----&amp;gt;       P1+&lt;br /&gt;
* Pot 6-P1W	-----&amp;gt;       P1-&lt;br /&gt;
* Pot 7-P1A	-----&amp;gt;      NC&lt;br /&gt;
* Pot 8-P0A     -----&amp;gt;       NC&lt;br /&gt;
* Pot 9-P0W    -----&amp;gt;       P0-&lt;br /&gt;
* Pot 10-P0B   -----&amp;gt;       P0+&lt;br /&gt;
* Pot 11 -WP   -----&amp;gt;       NC&lt;br /&gt;
* Pot 12 - SHDN -----&amp;gt;    3.3v (this pin is inverse-shutdown, so we keep it high)&lt;br /&gt;
* Pot 13-SDO  -----&amp;gt;       C4&lt;br /&gt;
* Pot 14-VDD  -----&amp;gt;       3.3v&lt;br /&gt;
&lt;br /&gt;
The resistance across PXB and PXW is what changes, labeled above as Px+ and Px-.&lt;br /&gt;
&lt;br /&gt;
== Library Functions ==&lt;br /&gt;
Code: [[Media:MCP42X1.h|MCP42X1.h]], [[Media:MCP42X1.c|MCP42X1.c]]&lt;br /&gt;
&lt;br /&gt;
Full example project: [[Media:MCP42X1_Example.zip]]&lt;br /&gt;
&lt;br /&gt;
MCP42X1.c contains the following functions:&lt;br /&gt;
&lt;br /&gt;
* void SPI_initPots() : sets up SPI channel 1, and CS pin&lt;br /&gt;
* void incPot(int pot_num) : will increment wiper by one step&lt;br /&gt;
* void decPot(int pot_num) : will decrement wiper by one step&lt;br /&gt;
* int setPot(int pot_num, int wiper) : sets the given pot to specific wiper value (0 - 127), returns success boolean&lt;br /&gt;
* int readPot(int pot_num) : reads the current wiper setting from the pot, returns (0 - 127)&lt;br /&gt;
* void testPots() : runs tests of setting, incrementing, decrementing, and reading both channels to confirm pots are working properly&lt;br /&gt;
&lt;br /&gt;
== Sample Code ==&lt;br /&gt;
&lt;br /&gt;
Initialize and clear the LCD:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
  LcdInitialize();&lt;br /&gt;
  LcdClear();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>AndrewKessler</name></author>
	</entry>
	<entry>
		<id>https://hades.mech.northwestern.edu//index.php?title=File:MCP42X1.h&amp;diff=21452</id>
		<title>File:MCP42X1.h</title>
		<link rel="alternate" type="text/html" href="https://hades.mech.northwestern.edu//index.php?title=File:MCP42X1.h&amp;diff=21452"/>
		<updated>2012-07-14T18:09:50Z</updated>

		<summary type="html">&lt;p&gt;AndrewKessler: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>AndrewKessler</name></author>
	</entry>
	<entry>
		<id>https://hades.mech.northwestern.edu//index.php?title=File:MCP42X1.c&amp;diff=21451</id>
		<title>File:MCP42X1.c</title>
		<link rel="alternate" type="text/html" href="https://hades.mech.northwestern.edu//index.php?title=File:MCP42X1.c&amp;diff=21451"/>
		<updated>2012-07-14T18:09:31Z</updated>

		<summary type="html">&lt;p&gt;AndrewKessler: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>AndrewKessler</name></author>
	</entry>
	<entry>
		<id>https://hades.mech.northwestern.edu//index.php?title=NU32:_Using_the_MCP42X1_SPI_Digital_Potentiometer&amp;diff=21450</id>
		<title>NU32: Using the MCP42X1 SPI Digital Potentiometer</title>
		<link rel="alternate" type="text/html" href="https://hades.mech.northwestern.edu//index.php?title=NU32:_Using_the_MCP42X1_SPI_Digital_Potentiometer&amp;diff=21450"/>
		<updated>2012-07-14T17:52:07Z</updated>

		<summary type="html">&lt;p&gt;AndrewKessler: /* Overview */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
The MCP42X1 is a 7-bit dual digital potentiometer. It is available in total resistance options of 5, 10, 50 and 100 kOhm. It is controlled using SPI communication and a digital output (CS). It has two independent potentiometer channels, each with its own wiper.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
A potentiometer is useful in a variety of circumstances when a variable resistance is needed. A digital potentiometer provides a variable resistor that can be controlled from a microcontroller. Because the MCP42X1 is a 7-bit device, there are 2^7 = 128 possible resistance &amp;quot;steps&amp;quot;. By communicating with the IC over SPI, we can choose what step (and thus, resistance) the potentiometer is set at. &lt;br /&gt;
&lt;br /&gt;
[[image:mcp42x1.png|thumb|300px|MCP42X1 Pinout|right]]&lt;br /&gt;
&lt;br /&gt;
The resistance across the PxB and PxW (the wiper) is governed by&lt;br /&gt;
&amp;lt;math&amp;gt;R_{WB} = \frac{5\Omega;}{128} N&amp;lt;/math&amp;gt;&lt;br /&gt;
where the 5kOhm comes from the total resistance of the pot, depending on the model. The value N is the setting of the pot between 0 and 127. &lt;br /&gt;
&lt;br /&gt;
The pot requires four communication pins from a microcontroller: SPI CLK,  SDO, SDI, and one digital output.  The pot is powered with 3.3V. This model is a dual pot chip, meaning it has two completely independent potentiometer channels in the same IC, referred to as Pot 0 and Pot 1, respectively.&lt;br /&gt;
&lt;br /&gt;
== Details ==&lt;br /&gt;
[[Media:MCP42X1.pdf|Datasheet]]&lt;br /&gt;
&lt;br /&gt;
Example schematic when communicating with the NU32, using SPI channel 1:&lt;br /&gt;
* Pot 1-CS        -----&amp;gt;	   F3&lt;br /&gt;
* Pot 2-SCK      -----&amp;gt;	   D10&lt;br /&gt;
* Pot 3-SDI       -----&amp;gt;	   D0&lt;br /&gt;
* Pot 4-VSS	-----&amp;gt;	   GND&lt;br /&gt;
* Pot 5-P1B	-----&amp;gt;       P1+&lt;br /&gt;
* Pot 6-P1W	-----&amp;gt;       P1-&lt;br /&gt;
* Pot 7-P1A	-----&amp;gt;      NC&lt;br /&gt;
* Pot 8-P0A     -----&amp;gt;       NC&lt;br /&gt;
* Pot 9-P0W    -----&amp;gt;       P0-&lt;br /&gt;
* Pot 10-P0B   -----&amp;gt;       P0+&lt;br /&gt;
* Pot 11 -WP   -----&amp;gt;       NC&lt;br /&gt;
* Pot 12 - SHDN -----&amp;gt;    3.3v (this pin is inverse-shutdown, so we keep it high)&lt;br /&gt;
* Pot 13-SDO  -----&amp;gt;       C4&lt;br /&gt;
* Pot 14-VDD  -----&amp;gt;       3.3v&lt;br /&gt;
&lt;br /&gt;
The resistance across PXB and PXW is what changes, labeled above as Px+ and Px-.&lt;br /&gt;
&lt;br /&gt;
== Library Functions ==&lt;br /&gt;
Code: [[Media:MCP42X1.h|MCP42X1.h]], [[Media:MCP42X1.c|MCP42X1.c]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
MCP42X1.c contains the following functions:&lt;br /&gt;
&lt;br /&gt;
* void SPI_initPots() : sets up SPI channel 1, and CS pin&lt;br /&gt;
* void incPot(int pot_num) : will increment wiper by one step&lt;br /&gt;
* void decPot(int pot_num) : will decrement wiper by one step&lt;br /&gt;
* int setPot(int pot_num, int wiper) : sets the given pot to specific wiper value (0 - 127), returns success boolean&lt;br /&gt;
* int readPot(int pot_num) : reads the current wiper setting from the pot, returns (0 - 127)&lt;br /&gt;
* void testPots() : runs tests of setting, incrementing, decrementing, and reading both channels to confirm pots are working properly&lt;br /&gt;
&lt;br /&gt;
== Sample Code ==&lt;br /&gt;
&lt;br /&gt;
Initialize and clear the LCD:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
  LcdInitialize();&lt;br /&gt;
  LcdClear();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>AndrewKessler</name></author>
	</entry>
	<entry>
		<id>https://hades.mech.northwestern.edu//index.php?title=File:Mcp42x1.png&amp;diff=21449</id>
		<title>File:Mcp42x1.png</title>
		<link rel="alternate" type="text/html" href="https://hades.mech.northwestern.edu//index.php?title=File:Mcp42x1.png&amp;diff=21449"/>
		<updated>2012-07-14T17:50:17Z</updated>

		<summary type="html">&lt;p&gt;AndrewKessler: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>AndrewKessler</name></author>
	</entry>
	<entry>
		<id>https://hades.mech.northwestern.edu//index.php?title=NU32:_Using_the_MCP42X1_SPI_Digital_Potentiometer&amp;diff=21448</id>
		<title>NU32: Using the MCP42X1 SPI Digital Potentiometer</title>
		<link rel="alternate" type="text/html" href="https://hades.mech.northwestern.edu//index.php?title=NU32:_Using_the_MCP42X1_SPI_Digital_Potentiometer&amp;diff=21448"/>
		<updated>2012-07-14T17:49:47Z</updated>

		<summary type="html">&lt;p&gt;AndrewKessler: /* Overview */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
The MCP42X1 is a 7-bit dual digital potentiometer. It is available in total resistance options of 5, 10, 50 and 100 kOhm. It is controlled using SPI communication and a digital output (CS). It has two independent potentiometer channels, each with its own wiper.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
A potentiometer is useful in a variety of circumstances when a variable resistance is needed. A digital potentiometer provides a variable resistor that can be controlled from a microcontroller. Because the MCP42X1 is a 7-bit device, there are 2^7 = 128 possible resistance &amp;quot;steps&amp;quot;. By communicating with the IC over SPI, we can choose what step (and thus, resistance) the potentiometer is set at. &lt;br /&gt;
&lt;br /&gt;
[[File: mcp42x1.png]]&lt;br /&gt;
&lt;br /&gt;
The resistance across the PxB and PxW (the wiper) is governed by&lt;br /&gt;
&amp;lt;math&amp;gt;R_{WB} = \frac{5\Omega;}{128} N&amp;lt;/math&amp;gt;&lt;br /&gt;
where the 5kOhm comes from the total resistance of the pot, depending on the model. The value N is the setting of the pot between 0 and 127. &lt;br /&gt;
&lt;br /&gt;
The pot requires four communication pins from a microcontroller: SPI CLK,  SDO, SDI, and one digital output.  The pot is powered with 3.3V. This model is a dual pot chip, meaning it has two completely independent potentiometer channels in the same IC, referred to as Pot 0 and Pot 1, respectively.&lt;br /&gt;
&lt;br /&gt;
== Details ==&lt;br /&gt;
[[Media:MCP42X1.pdf|Datasheet]]&lt;br /&gt;
&lt;br /&gt;
Example schematic when communicating with the NU32, using SPI channel 1:&lt;br /&gt;
* Pot 1-CS        -----&amp;gt;	   F3&lt;br /&gt;
* Pot 2-SCK      -----&amp;gt;	   D10&lt;br /&gt;
* Pot 3-SDI       -----&amp;gt;	   D0&lt;br /&gt;
* Pot 4-VSS	-----&amp;gt;	   GND&lt;br /&gt;
* Pot 5-P1B	-----&amp;gt;       P1+&lt;br /&gt;
* Pot 6-P1W	-----&amp;gt;       P1-&lt;br /&gt;
* Pot 7-P1A	-----&amp;gt;      NC&lt;br /&gt;
* Pot 8-P0A     -----&amp;gt;       NC&lt;br /&gt;
* Pot 9-P0W    -----&amp;gt;       P0-&lt;br /&gt;
* Pot 10-P0B   -----&amp;gt;       P0+&lt;br /&gt;
* Pot 11 -WP   -----&amp;gt;       NC&lt;br /&gt;
* Pot 12 - SHDN -----&amp;gt;    3.3v (this pin is inverse-shutdown, so we keep it high)&lt;br /&gt;
* Pot 13-SDO  -----&amp;gt;       C4&lt;br /&gt;
* Pot 14-VDD  -----&amp;gt;       3.3v&lt;br /&gt;
&lt;br /&gt;
The resistance across PXB and PXW is what changes, labeled above as Px+ and Px-.&lt;br /&gt;
&lt;br /&gt;
== Library Functions ==&lt;br /&gt;
Code: [[Media:MCP42X1.h|MCP42X1.h]], [[Media:MCP42X1.c|MCP42X1.c]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
MCP42X1.c contains the following functions:&lt;br /&gt;
&lt;br /&gt;
* void SPI_initPots() : sets up SPI channel 1, and CS pin&lt;br /&gt;
* void incPot(int pot_num) : will increment wiper by one step&lt;br /&gt;
* void decPot(int pot_num) : will decrement wiper by one step&lt;br /&gt;
* int setPot(int pot_num, int wiper) : sets the given pot to specific wiper value (0 - 127), returns success boolean&lt;br /&gt;
* int readPot(int pot_num) : reads the current wiper setting from the pot, returns (0 - 127)&lt;br /&gt;
* void testPots() : runs tests of setting, incrementing, decrementing, and reading both channels to confirm pots are working properly&lt;br /&gt;
&lt;br /&gt;
== Sample Code ==&lt;br /&gt;
&lt;br /&gt;
Initialize and clear the LCD:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
  LcdInitialize();&lt;br /&gt;
  LcdClear();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>AndrewKessler</name></author>
	</entry>
	<entry>
		<id>https://hades.mech.northwestern.edu//index.php?title=NU32:_Using_the_MCP42X1_SPI_Digital_Potentiometer&amp;diff=21447</id>
		<title>NU32: Using the MCP42X1 SPI Digital Potentiometer</title>
		<link rel="alternate" type="text/html" href="https://hades.mech.northwestern.edu//index.php?title=NU32:_Using_the_MCP42X1_SPI_Digital_Potentiometer&amp;diff=21447"/>
		<updated>2012-07-14T17:46:53Z</updated>

		<summary type="html">&lt;p&gt;AndrewKessler: /* Details */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
The MCP42X1 is a 7-bit dual digital potentiometer. It is available in total resistance options of 5, 10, 50 and 100 kOhm. It is controlled using SPI communication and a digital output (CS). It has two independent potentiometer channels, each with its own wiper.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
A potentiometer is useful in a variety of circumstances when a variable resistance is needed. A digital potentiometer provides a variable resistor that can be controlled from a microcontroller. Because the MCP42X1 is a 7-bit device, there are 2^7 = 128 possible resistance &amp;quot;steps&amp;quot;. By communicating with the IC over SPI, we can choose what step (and thus, resistance) the potentiometer is set at. &lt;br /&gt;
&lt;br /&gt;
The resistance across the PxB and PxW (the wiper) is governed by&lt;br /&gt;
&amp;lt;math&amp;gt;R_{WB} = \frac{5\Omega;}{128} N&amp;lt;/math&amp;gt;&lt;br /&gt;
where the 5kOhm comes from the total resistance of the pot, depending on the model. The value N is the setting of the pot between 0 and 127. &lt;br /&gt;
&lt;br /&gt;
The pot requires four communication pins from a microcontroller: SPI CLK,  SDO, SDI, and one digital output.  The pot is powered with 3.3V. This model is a dual pot chip, meaning it has two completely independent potentiometer channels in the same IC, referred to as Pot 0 and Pot 1, respectively.&lt;br /&gt;
&lt;br /&gt;
== Details ==&lt;br /&gt;
[[Media:MCP42X1.pdf|Datasheet]]&lt;br /&gt;
&lt;br /&gt;
Example schematic when communicating with the NU32, using SPI channel 1:&lt;br /&gt;
* Pot 1-CS        -----&amp;gt;	   F3&lt;br /&gt;
* Pot 2-SCK      -----&amp;gt;	   D10&lt;br /&gt;
* Pot 3-SDI       -----&amp;gt;	   D0&lt;br /&gt;
* Pot 4-VSS	-----&amp;gt;	   GND&lt;br /&gt;
* Pot 5-P1B	-----&amp;gt;       P1+&lt;br /&gt;
* Pot 6-P1W	-----&amp;gt;       P1-&lt;br /&gt;
* Pot 7-P1A	-----&amp;gt;      NC&lt;br /&gt;
* Pot 8-P0A     -----&amp;gt;       NC&lt;br /&gt;
* Pot 9-P0W    -----&amp;gt;       P0-&lt;br /&gt;
* Pot 10-P0B   -----&amp;gt;       P0+&lt;br /&gt;
* Pot 11 -WP   -----&amp;gt;       NC&lt;br /&gt;
* Pot 12 - SHDN -----&amp;gt;    3.3v (this pin is inverse-shutdown, so we keep it high)&lt;br /&gt;
* Pot 13-SDO  -----&amp;gt;       C4&lt;br /&gt;
* Pot 14-VDD  -----&amp;gt;       3.3v&lt;br /&gt;
&lt;br /&gt;
The resistance across PXB and PXW is what changes, labeled above as Px+ and Px-.&lt;br /&gt;
&lt;br /&gt;
== Library Functions ==&lt;br /&gt;
Code: [[Media:MCP42X1.h|MCP42X1.h]], [[Media:MCP42X1.c|MCP42X1.c]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
MCP42X1.c contains the following functions:&lt;br /&gt;
&lt;br /&gt;
* void SPI_initPots() : sets up SPI channel 1, and CS pin&lt;br /&gt;
* void incPot(int pot_num) : will increment wiper by one step&lt;br /&gt;
* void decPot(int pot_num) : will decrement wiper by one step&lt;br /&gt;
* int setPot(int pot_num, int wiper) : sets the given pot to specific wiper value (0 - 127), returns success boolean&lt;br /&gt;
* int readPot(int pot_num) : reads the current wiper setting from the pot, returns (0 - 127)&lt;br /&gt;
* void testPots() : runs tests of setting, incrementing, decrementing, and reading both channels to confirm pots are working properly&lt;br /&gt;
&lt;br /&gt;
== Sample Code ==&lt;br /&gt;
&lt;br /&gt;
Initialize and clear the LCD:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
  LcdInitialize();&lt;br /&gt;
  LcdClear();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>AndrewKessler</name></author>
	</entry>
	<entry>
		<id>https://hades.mech.northwestern.edu//index.php?title=NU32:_Using_the_MCP42X1_SPI_Digital_Potentiometer&amp;diff=21446</id>
		<title>NU32: Using the MCP42X1 SPI Digital Potentiometer</title>
		<link rel="alternate" type="text/html" href="https://hades.mech.northwestern.edu//index.php?title=NU32:_Using_the_MCP42X1_SPI_Digital_Potentiometer&amp;diff=21446"/>
		<updated>2012-07-14T17:41:20Z</updated>

		<summary type="html">&lt;p&gt;AndrewKessler: /* Library Functions */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
The MCP42X1 is a 7-bit dual digital potentiometer. It is available in total resistance options of 5, 10, 50 and 100 kOhm. It is controlled using SPI communication and a digital output (CS). It has two independent potentiometer channels, each with its own wiper.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
A potentiometer is useful in a variety of circumstances when a variable resistance is needed. A digital potentiometer provides a variable resistor that can be controlled from a microcontroller. Because the MCP42X1 is a 7-bit device, there are 2^7 = 128 possible resistance &amp;quot;steps&amp;quot;. By communicating with the IC over SPI, we can choose what step (and thus, resistance) the potentiometer is set at. &lt;br /&gt;
&lt;br /&gt;
The resistance across the PxB and PxW (the wiper) is governed by&lt;br /&gt;
&amp;lt;math&amp;gt;R_{WB} = \frac{5\Omega;}{128} N&amp;lt;/math&amp;gt;&lt;br /&gt;
where the 5kOhm comes from the total resistance of the pot, depending on the model. The value N is the setting of the pot between 0 and 127. &lt;br /&gt;
&lt;br /&gt;
The pot requires four communication pins from a microcontroller: SPI CLK,  SDO, SDI, and one digital output.  The pot is powered with 3.3V. This model is a dual pot chip, meaning it has two completely independent potentiometer channels in the same IC, referred to as Pot 0 and Pot 1, respectively.&lt;br /&gt;
&lt;br /&gt;
== Details ==&lt;br /&gt;
[[Media:MCP42X1.pdf|Datasheet]]&lt;br /&gt;
&lt;br /&gt;
Example schematic when communicating with the NU32, using SPI channel 1:&lt;br /&gt;
* Pot 1-CS        -----&amp;gt;	   F3&lt;br /&gt;
* Pot 2-SCK      -----&amp;gt;	   D10&lt;br /&gt;
* Pot 3-SDI       -----&amp;gt;	   D0&lt;br /&gt;
* Pot 4-VSS	-----&amp;gt;	   GND&lt;br /&gt;
* Pot 5-P1B	-----&amp;gt;       P1+&lt;br /&gt;
* Pot 6-P1W	-----&amp;gt;       P1-&lt;br /&gt;
* Pot 7-P1A	-----&amp;gt;      NC&lt;br /&gt;
* Pot 8-P0A     -----&amp;gt;       NC&lt;br /&gt;
* Pot 9-P0W    -----&amp;gt;       P0-&lt;br /&gt;
* Pot 10-P0B   -----&amp;gt;       P0+&lt;br /&gt;
* Pot 11 -WP   -----&amp;gt;       NC&lt;br /&gt;
* Pot 12 - SHDN -----&amp;gt;      3.3v&lt;br /&gt;
* Pot 13-SDO  -----&amp;gt;       C4&lt;br /&gt;
* Pot 14-VDD  -----&amp;gt;       3.3v&lt;br /&gt;
&lt;br /&gt;
The resistance across PXB and PXW is what changes, labeled above as Px+ and Px-.&lt;br /&gt;
&lt;br /&gt;
== Library Functions ==&lt;br /&gt;
Code: [[Media:MCP42X1.h|MCP42X1.h]], [[Media:MCP42X1.c|MCP42X1.c]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
MCP42X1.c contains the following functions:&lt;br /&gt;
&lt;br /&gt;
* void SPI_initPots() : sets up SPI channel 1, and CS pin&lt;br /&gt;
* void incPot(int pot_num) : will increment wiper by one step&lt;br /&gt;
* void decPot(int pot_num) : will decrement wiper by one step&lt;br /&gt;
* int setPot(int pot_num, int wiper) : sets the given pot to specific wiper value (0 - 127), returns success boolean&lt;br /&gt;
* int readPot(int pot_num) : reads the current wiper setting from the pot, returns (0 - 127)&lt;br /&gt;
* void testPots() : runs tests of setting, incrementing, decrementing, and reading both channels to confirm pots are working properly&lt;br /&gt;
&lt;br /&gt;
== Sample Code ==&lt;br /&gt;
&lt;br /&gt;
Initialize and clear the LCD:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
  LcdInitialize();&lt;br /&gt;
  LcdClear();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>AndrewKessler</name></author>
	</entry>
	<entry>
		<id>https://hades.mech.northwestern.edu//index.php?title=Microchip_PICs&amp;diff=21445</id>
		<title>Microchip PICs</title>
		<link rel="alternate" type="text/html" href="https://hades.mech.northwestern.edu//index.php?title=Microchip_PICs&amp;diff=21445"/>
		<updated>2012-07-14T17:33:04Z</updated>

		<summary type="html">&lt;p&gt;AndrewKessler: /* Using the NU32 (Winter 2012 and on) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;#039;&amp;#039;&amp;#039;Note:  Some of the code on the bottom of this page was written using the CCS compiler.  All new code is being written using Microchip&amp;#039;s MPLAB X.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;[http://peshkin.mech.northwestern.edu/pic/code Link to all PIC18F sample code here.]&amp;lt;/b&amp;gt;&lt;br /&gt;
*[[Sample code for most PIC18F4520 operations]]&lt;br /&gt;
*[http://www.ccsinfo.com/forum/ CCS user forum]&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
__TOC__&lt;br /&gt;
== The NUScope ==&lt;br /&gt;
*[[NUScope]]&lt;br /&gt;
== Using the NU32 (Winter 2012 and on) ==&lt;br /&gt;
*[[NU32: Introduction to the PIC32]]&lt;br /&gt;
**[[NU32: What is in the NU32 Kit]]&lt;br /&gt;
**[[NU32: Software to Install]]&lt;br /&gt;
**[[NU32: Starting a New Project and Putting it on the NU32]]&lt;br /&gt;
**[[NU32: A Detailed Look at Programming the PIC32 on the NU32]]&lt;br /&gt;
* Sample Code&lt;br /&gt;
**[[NU32: Serial Communication with the PC]]&lt;br /&gt;
**[[NU32: 16x2 LCD]]&lt;br /&gt;
**[[NU32: Digital Input and Output]]&lt;br /&gt;
**[[NU32: Counters and Timers]]&lt;br /&gt;
**[[NU32: Interrupts]]&lt;br /&gt;
**[[NU32: Output Compare, PWM, and Analog Output]]&lt;br /&gt;
**[[NU32: Analog Input]]&lt;br /&gt;
**[[NU32: Using the dsPIC33FJ12MC201 QEI to SPI board]]&lt;br /&gt;
**[[NU32: Using the MAX9918 current sensor]]&lt;br /&gt;
**[[NU32: Using the TB6612 H-Bridge]]&lt;br /&gt;
**[[NU32: Driving RC servo motors]]&lt;br /&gt;
**[[NU32: Driving a stepper motor]]&lt;br /&gt;
**[[NU32: Using the LS7183 Quadrature Clock Converter]]&lt;br /&gt;
**[[NU32: Using the L293D H-Bridge]]&lt;br /&gt;
**[[NU32: Using the MCP42X1 SPI Digital Potentiometer]]&lt;br /&gt;
**[[NU32: Digital Signal Processing]]&lt;br /&gt;
**[[NU32: Input Capture]]&lt;br /&gt;
**[[NU32: Flash Self-Programming]]&lt;br /&gt;
**[[NU32: UART Asynchronous Serial Communication]]&lt;br /&gt;
**[[NU32: I2C Synchronous Serial Communication]]&lt;br /&gt;
**[[NU32: SPI Synchronous Serial Communication]]&lt;br /&gt;
**[[NU32: Watchdog Timer]]&lt;br /&gt;
**[[NU32: VC0706 Serial Camera]]&lt;br /&gt;
&lt;br /&gt;
== Using the NU32v2 (Winter 2011) ==&lt;br /&gt;
*[[NU32v2: Introduction to the PIC32]]&lt;br /&gt;
**[[NU32v2: What is in the NU32v2 Kit]]&lt;br /&gt;
**[[NU32v2: Software to Install]]&lt;br /&gt;
**[[NU32v2: Starting a New Project and Putting it on the NU32v2]]&lt;br /&gt;
**[[NU32v2: Using the Simulator]]&lt;br /&gt;
**[[NU32v2: A Detailed Look at Programming the PIC32]]&lt;br /&gt;
**[[NU32v2: Benchmark Test]]&lt;br /&gt;
* Sample Code&lt;br /&gt;
**[[NU32v2: Digital Input and Output]]&lt;br /&gt;
**[[NU32v2: Counters and Timers]]&lt;br /&gt;
**[[NU32v2: Interrupts]]&lt;br /&gt;
**[[NU32v2: Output Compare, PWM, and Analog Output]]&lt;br /&gt;
**[[NU32v2: Serial Communication with the PC]]&lt;br /&gt;
**[[NU32v2: Nokia 5110 LCD]]&lt;br /&gt;
**[[NU32v2: Analog Input]]&lt;br /&gt;
**[[NU32v2: Using the LS7183 Quadrature Clock Converter]]&lt;br /&gt;
**[[NU32v2: Using the L293D H-Bridge]]&lt;br /&gt;
**[[NU32v2: Input Capture]]&lt;br /&gt;
**[[NU32v2: Flash Self-Programming]]&lt;br /&gt;
**[[NU32v2: UART Asynchronous Serial Communication]]&lt;br /&gt;
**[[NU32v2: I2C Synchronous Serial Communication]]&lt;br /&gt;
**[[NU32v2: SPI Synchronous Serial Communication]]&lt;br /&gt;
**[[NU32v2: Digital Signal Processing]]&lt;br /&gt;
**[[NU32v2: Watchdog Timer]]&lt;br /&gt;
**[[NU32v2: Simple Analog Input]]&lt;br /&gt;
&lt;br /&gt;
== Using the PIC18F4520 ==&lt;br /&gt;
*[[4520 Board intro]]&lt;br /&gt;
*[[4520 Board construction]]&lt;br /&gt;
*[[4520 Board use]]&lt;br /&gt;
*[[Microcontroller PIC18F4520]]&lt;br /&gt;
*[[PIC MCUs: Capabilities of PIC18F4520]]&lt;br /&gt;
**[[PIC18F4520: PWM Motor Control]]&lt;br /&gt;
**[[PIC18F4520: Digital Outputs]]&lt;br /&gt;
**[[PIC18F4520: Digital Inputs]]&lt;br /&gt;
**[[PIC18F4520: Serial Digital-to-Analog Conversion]]&lt;br /&gt;
**[[PIC18F4520: Analog Inputs]]&lt;br /&gt;
**[[PIC18F4520: Timers]]&lt;br /&gt;
**[[PIC18F4520: Comparator]]&lt;br /&gt;
&lt;br /&gt;
== Example Code in C for PIC18F4520==&lt;br /&gt;
*[[C Example: Parallel Interfacing with LCDs]]&lt;br /&gt;
*[[C Example: Digital Inputs]]&lt;br /&gt;
*[[C Example: PWM Motor Control]]&lt;br /&gt;
*[[C Example: Comparators]]&lt;br /&gt;
*[[C Example: Digital Outputs]]&lt;br /&gt;
*[[C Example: Analog Inputs]]&lt;br /&gt;
*[[C Example: Digital Outputs (Ports)]]&lt;br /&gt;
*[[C Example: Bi-Directional PWM Motor Control]]&lt;br /&gt;
*[[C Example: Serial LCD]]&lt;br /&gt;
&lt;br /&gt;
== Using the PIC32MX Series ==&lt;br /&gt;
*[[Introduction to the PIC32]]&lt;br /&gt;
*[[Getting Started with PIC32]] (includes NU32 development board)&lt;br /&gt;
** Download PIC32 Tutorial Files [[Media: PIC32_TutorialFiles.zip|here]].&lt;br /&gt;
** [[ME 333 Lab 2]] - Includes Digital IO, Analog Input, Parallel LCD and RS232 Com&lt;br /&gt;
** [[ME 333 Lab 4]] - Includes PWM and Encoder Motor Control&lt;br /&gt;
*[[Microcontroller PIC32MX460F512L]]&lt;br /&gt;
*[[Programming HID Bootloader on PIC32]] &lt;br /&gt;
*[[HelloWorld PIC32|Directions to code HelloWorld]]&lt;br /&gt;
*[[Directions to Load Files to PIC32 with HID Bootloader]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*[[PIC MCUs: Capabilities of PIC32MX]]&lt;br /&gt;
**[[Programming HID Bootloader on PIC32 |PIC32MX: Bootloader]]&lt;br /&gt;
**Simple Programs&lt;br /&gt;
***[[PIC32MX: Digital Inputs]]&lt;br /&gt;
***[[PIC32MX: Digital Outputs]]&lt;br /&gt;
***[[PIC32MX: Analog Inputs]]&lt;br /&gt;
**Communication&lt;br /&gt;
***[[PIC32MX: Parallel LCD]]&lt;br /&gt;
***[[PIC32MX: RS232]]&lt;br /&gt;
***[[PIC32MX:  USB Communication with a PC]]&lt;br /&gt;
***[[PIC32MX:  SPI External RAM]]&lt;br /&gt;
***[[PIC32MX:  I2C DAC]]&lt;br /&gt;
***[[PIC32MX:  I2C EEPROM]]&lt;br /&gt;
***[[PIC32MX:  SPI EEPROM]]&lt;br /&gt;
***[[PIC32MX:  I2C Communication between PIC32s]]&lt;br /&gt;
***[[PIC32MX:  SPI Communication between PIC32s]]&lt;br /&gt;
**Motor Control&lt;br /&gt;
***[[PIC32MX: PWM Motor Control|PIC32MX: PWM Motor Control]]&lt;br /&gt;
***[[PIC32MX: Encoder Motor Control|PIC32MX: Encoder Motor Control]]&lt;br /&gt;
***[[PIC32MX: Servo Control|PIC32MX: Servo Control]]&lt;br /&gt;
***[[PIC32MX:  Driving a Stepper Motor]]&lt;br /&gt;
***[[Using the LS7166 Quadrature Counter]]&lt;br /&gt;
***[[Using the LS7366R SPI Quadrature Counter]]&lt;br /&gt;
**Capabilities&lt;br /&gt;
***[[PIC32MX:  Benchmarking Mathematical Operations]]&lt;br /&gt;
***[[PIC32MX:  FFT of Analog Input]]&lt;br /&gt;
***[[PIC32MX:  Sinusoidal Analog Output]]&lt;br /&gt;
***[[PIC32MX:  XBee Wireless Round-trip Latency]]&lt;br /&gt;
***[[PIC32MX:  Interfacing with Force Sensors from a Scale]]&lt;br /&gt;
***[[PIC32MX:  Storing Data in Flash Memory (Run-Time Self Programming)]]&lt;br /&gt;
&lt;br /&gt;
==Other PIC Resources ==&lt;br /&gt;
&lt;br /&gt;
*[[PIC PWM Motor Driver]]&lt;br /&gt;
*[[Writing Code with the C18 Compiler]]&lt;br /&gt;
*[[Controlling a seven segment display]]&lt;br /&gt;
*[[PIC Microcontrollers with C18 Compiler]]&lt;br /&gt;
*[[PIC Motor Control and Serial Port Example]]&lt;br /&gt;
*[[PIC16F684]]&lt;br /&gt;
*[[PIC Microcontrollers with CCS Compiler]]&lt;br /&gt;
*[[Stepper motor control with the PIC]]&lt;br /&gt;
*[[PIC/C18 Compiler Tips and Troubleshooting]]&lt;br /&gt;
*[[CCS C]]&lt;br /&gt;
*[[Analog Input]]&lt;br /&gt;
*[[PIC MCUs: Hardware and Connections]]&lt;br /&gt;
*[[Storing constant data in program memory]]&lt;br /&gt;
*[[PIC Analog-Digital-Converter Example]]&lt;br /&gt;
*[[PIC Microcontroller]]&lt;br /&gt;
*[[Digital inputs &amp;amp; outputs]]&lt;br /&gt;
*[[Debugging C on a PIC]]&lt;br /&gt;
*[[Analog Output]]&lt;br /&gt;
*[[PIC MCUs: Software]]&lt;br /&gt;
*[[Interfacing to External EEPROM]]&lt;br /&gt;
*[[CCS IDE]]&lt;br /&gt;
*[[Interrupts]]&lt;br /&gt;
*[[PIC16F684 Registers]]&lt;br /&gt;
*[[Waveform Generation with AD9833]]&lt;br /&gt;
*[[Waveform Generation with AD9833, and SPI]]&lt;br /&gt;
*[[PIC computation time benchmarks]]&lt;br /&gt;
*[[PICkit 1]]&lt;br /&gt;
*[[PIC MCUs: 4520 Board]]&lt;br /&gt;
*[[More debugging tips]]&lt;br /&gt;
*[[Example Writeup: Analog Input]]&lt;br /&gt;
*[[LED Drivers]]&lt;br /&gt;
*[[Embedded Programming Tips for CCS C]]&lt;br /&gt;
*[[Wireless PIC bootloading]]&lt;br /&gt;
*[[PIC 18f4553]]&lt;br /&gt;
*[[I2C Motor Controller]]&lt;br /&gt;
*[[Driving a piezo speaker with a PIC]]&lt;br /&gt;
*[[PIC Servo Controller]]&lt;br /&gt;
*[[Watchdog timer]]&lt;br /&gt;
*[[Interfacing PIC with SPI memory]]&lt;br /&gt;
*[[Using the LS7166 Quadrature Counter]]&lt;br /&gt;
&lt;br /&gt;
==Programming the PIC with Microchip&amp;#039;s MPLAB==&lt;/div&gt;</summary>
		<author><name>AndrewKessler</name></author>
	</entry>
	<entry>
		<id>https://hades.mech.northwestern.edu//index.php?title=NU32:_Using_the_MCP42X1_SPI_Digital_Potentiometer&amp;diff=21444</id>
		<title>NU32: Using the MCP42X1 SPI Digital Potentiometer</title>
		<link rel="alternate" type="text/html" href="https://hades.mech.northwestern.edu//index.php?title=NU32:_Using_the_MCP42X1_SPI_Digital_Potentiometer&amp;diff=21444"/>
		<updated>2012-07-14T15:29:51Z</updated>

		<summary type="html">&lt;p&gt;AndrewKessler: /* Details */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
The MCP42X1 is a 7-bit dual digital potentiometer. It is available in total resistance options of 5, 10, 50 and 100 kOhm. It is controlled using SPI communication and a digital output (CS). It has two independent potentiometer channels, each with its own wiper.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
A potentiometer is useful in a variety of circumstances when a variable resistance is needed. A digital potentiometer provides a variable resistor that can be controlled from a microcontroller. Because the MCP42X1 is a 7-bit device, there are 2^7 = 128 possible resistance &amp;quot;steps&amp;quot;. By communicating with the IC over SPI, we can choose what step (and thus, resistance) the potentiometer is set at. &lt;br /&gt;
&lt;br /&gt;
The resistance across the PxB and PxW (the wiper) is governed by&lt;br /&gt;
&amp;lt;math&amp;gt;R_{WB} = \frac{5\Omega;}{128} N&amp;lt;/math&amp;gt;&lt;br /&gt;
where the 5kOhm comes from the total resistance of the pot, depending on the model. The value N is the setting of the pot between 0 and 127. &lt;br /&gt;
&lt;br /&gt;
The pot requires four communication pins from a microcontroller: SPI CLK,  SDO, SDI, and one digital output.  The pot is powered with 3.3V. This model is a dual pot chip, meaning it has two completely independent potentiometer channels in the same IC, referred to as Pot 0 and Pot 1, respectively.&lt;br /&gt;
&lt;br /&gt;
== Details ==&lt;br /&gt;
[[Media:MCP42X1.pdf|Datasheet]]&lt;br /&gt;
&lt;br /&gt;
Example schematic when communicating with the NU32, using SPI channel 1:&lt;br /&gt;
* Pot 1-CS        -----&amp;gt;	   F3&lt;br /&gt;
* Pot 2-SCK      -----&amp;gt;	   D10&lt;br /&gt;
* Pot 3-SDI       -----&amp;gt;	   D0&lt;br /&gt;
* Pot 4-VSS	-----&amp;gt;	   GND&lt;br /&gt;
* Pot 5-P1B	-----&amp;gt;       P1+&lt;br /&gt;
* Pot 6-P1W	-----&amp;gt;       P1-&lt;br /&gt;
* Pot 7-P1A	-----&amp;gt;      NC&lt;br /&gt;
* Pot 8-P0A     -----&amp;gt;       NC&lt;br /&gt;
* Pot 9-P0W    -----&amp;gt;       P0-&lt;br /&gt;
* Pot 10-P0B   -----&amp;gt;       P0+&lt;br /&gt;
* Pot 11 -WP   -----&amp;gt;       NC&lt;br /&gt;
* Pot 12 - SHDN -----&amp;gt;      3.3v&lt;br /&gt;
* Pot 13-SDO  -----&amp;gt;       C4&lt;br /&gt;
* Pot 14-VDD  -----&amp;gt;       3.3v&lt;br /&gt;
&lt;br /&gt;
The resistance across PXB and PXW is what changes, labeled above as Px+ and Px-.&lt;br /&gt;
&lt;br /&gt;
== Library Functions ==&lt;br /&gt;
Code: [[Media:MCP42X1.h|MCP42X1.h]], [[Media:MCP42X1.c|MCP42X1.c]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
MCP42X1.c contains the following functions:&lt;br /&gt;
&lt;br /&gt;
== Sample Code ==&lt;br /&gt;
&lt;br /&gt;
Initialize and clear the LCD:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
  LcdInitialize();&lt;br /&gt;
  LcdClear();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>AndrewKessler</name></author>
	</entry>
	<entry>
		<id>https://hades.mech.northwestern.edu//index.php?title=File:MCP42X1.pdf&amp;diff=21443</id>
		<title>File:MCP42X1.pdf</title>
		<link rel="alternate" type="text/html" href="https://hades.mech.northwestern.edu//index.php?title=File:MCP42X1.pdf&amp;diff=21443"/>
		<updated>2012-07-14T15:29:18Z</updated>

		<summary type="html">&lt;p&gt;AndrewKessler: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>AndrewKessler</name></author>
	</entry>
	<entry>
		<id>https://hades.mech.northwestern.edu//index.php?title=NU32:_Using_the_MCP42X1_SPI_Digital_Potentiometer&amp;diff=21442</id>
		<title>NU32: Using the MCP42X1 SPI Digital Potentiometer</title>
		<link rel="alternate" type="text/html" href="https://hades.mech.northwestern.edu//index.php?title=NU32:_Using_the_MCP42X1_SPI_Digital_Potentiometer&amp;diff=21442"/>
		<updated>2012-07-14T15:27:47Z</updated>

		<summary type="html">&lt;p&gt;AndrewKessler: /* Overview */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
The MCP42X1 is a 7-bit dual digital potentiometer. It is available in total resistance options of 5, 10, 50 and 100 kOhm. It is controlled using SPI communication and a digital output (CS). It has two independent potentiometer channels, each with its own wiper.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
A potentiometer is useful in a variety of circumstances when a variable resistance is needed. A digital potentiometer provides a variable resistor that can be controlled from a microcontroller. Because the MCP42X1 is a 7-bit device, there are 2^7 = 128 possible resistance &amp;quot;steps&amp;quot;. By communicating with the IC over SPI, we can choose what step (and thus, resistance) the potentiometer is set at. &lt;br /&gt;
&lt;br /&gt;
The resistance across the PxB and PxW (the wiper) is governed by&lt;br /&gt;
&amp;lt;math&amp;gt;R_{WB} = \frac{5\Omega;}{128} N&amp;lt;/math&amp;gt;&lt;br /&gt;
where the 5kOhm comes from the total resistance of the pot, depending on the model. The value N is the setting of the pot between 0 and 127. &lt;br /&gt;
&lt;br /&gt;
The pot requires four communication pins from a microcontroller: SPI CLK,  SDO, SDI, and one digital output.  The pot is powered with 3.3V. This model is a dual pot chip, meaning it has two completely independent potentiometer channels in the same IC, referred to as Pot 0 and Pot 1, respectively.&lt;br /&gt;
&lt;br /&gt;
== Details ==&lt;br /&gt;
[[Media:mcp42X1.pdf|Datasheet]]&lt;br /&gt;
&lt;br /&gt;
Example schematic when communicating with the NU32, using SPI channel 1:&lt;br /&gt;
* Pot 1-CS        -----&amp;gt;	   F3&lt;br /&gt;
* Pot 2-SCK      -----&amp;gt;	   D10&lt;br /&gt;
* Pot 3-SDI       -----&amp;gt;	   D0&lt;br /&gt;
* Pot 4-VSS	-----&amp;gt;	   GND&lt;br /&gt;
* Pot 5-P1B	-----&amp;gt;       P1+&lt;br /&gt;
* Pot 6-P1W	-----&amp;gt;       P1-&lt;br /&gt;
* Pot 7-P1A	-----&amp;gt;      NC&lt;br /&gt;
* Pot 8-P0A     -----&amp;gt;       NC&lt;br /&gt;
* Pot 9-P0W    -----&amp;gt;       P0-&lt;br /&gt;
* Pot 10-P0B   -----&amp;gt;       P0+&lt;br /&gt;
* Pot 11 -WP   -----&amp;gt;       NC&lt;br /&gt;
* Pot 12 - SHDN -----&amp;gt;      3.3v&lt;br /&gt;
* Pot 13-SDO  -----&amp;gt;       C4&lt;br /&gt;
* Pot 14-VDD  -----&amp;gt;       3.3v&lt;br /&gt;
&lt;br /&gt;
The resistance across PXB and PXW is what changes, labeled above as Px+ and Px-.&lt;br /&gt;
&lt;br /&gt;
== Library Functions ==&lt;br /&gt;
Code: [[Media:MCP42X1.h|MCP42X1.h]], [[Media:MCP42X1.c|MCP42X1.c]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
MCP42X1.c contains the following functions:&lt;br /&gt;
&lt;br /&gt;
== Sample Code ==&lt;br /&gt;
&lt;br /&gt;
Initialize and clear the LCD:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
  LcdInitialize();&lt;br /&gt;
  LcdClear();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>AndrewKessler</name></author>
	</entry>
	<entry>
		<id>https://hades.mech.northwestern.edu//index.php?title=NU32:_Using_the_MCP42X1_SPI_Digital_Potentiometer&amp;diff=21441</id>
		<title>NU32: Using the MCP42X1 SPI Digital Potentiometer</title>
		<link rel="alternate" type="text/html" href="https://hades.mech.northwestern.edu//index.php?title=NU32:_Using_the_MCP42X1_SPI_Digital_Potentiometer&amp;diff=21441"/>
		<updated>2012-07-14T15:27:27Z</updated>

		<summary type="html">&lt;p&gt;AndrewKessler: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
The MCP42X1 is a 7-bit dual digital potentiometer. It is available in total resistance options of 5, 10, 50 and 100 kOhm. It is controlled using SPI communication and a digital output (CS). It has two independent potentiometer channels, each with its own wiper.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
A potentiometer is useful in a variety of circumstances when a variable resistance is needed. A digital potentiometer allows provides a variable resistor that can be controlled from a microcontroller. Because the MCP42X1 is a 7-bit device, there are 2^7 = 128 possible resistance &amp;quot;steps&amp;quot;. By communicating with the IC over SPI, we can choose what step (and thus, resistance) the potentiometer is set at. &lt;br /&gt;
&lt;br /&gt;
The resistance across the PxB and PxW (the wiper) is governed by&lt;br /&gt;
&amp;lt;math&amp;gt;R_{WB} = \frac{5\Omega;}{128} N&amp;lt;/math&amp;gt;&lt;br /&gt;
where the 5kOhm comes from the total resistance of the pot, depending on the model. The value N is the setting of the pot between 0 and 127. &lt;br /&gt;
&lt;br /&gt;
The pot requires four communication pins from a microcontroller: SPI CLK,  SDO, SDI, and one digital output.  The pot is powered with 3.3V. This model is a dual pot chip, meaning it has two completely independent potentiometer channels in the same IC, referred to as Pot 0 and Pot 1, respectively. &lt;br /&gt;
&lt;br /&gt;
== Details ==&lt;br /&gt;
[[Media:mcp42X1.pdf|Datasheet]]&lt;br /&gt;
&lt;br /&gt;
Example schematic when communicating with the NU32, using SPI channel 1:&lt;br /&gt;
* Pot 1-CS        -----&amp;gt;	   F3&lt;br /&gt;
* Pot 2-SCK      -----&amp;gt;	   D10&lt;br /&gt;
* Pot 3-SDI       -----&amp;gt;	   D0&lt;br /&gt;
* Pot 4-VSS	-----&amp;gt;	   GND&lt;br /&gt;
* Pot 5-P1B	-----&amp;gt;       P1+&lt;br /&gt;
* Pot 6-P1W	-----&amp;gt;       P1-&lt;br /&gt;
* Pot 7-P1A	-----&amp;gt;      NC&lt;br /&gt;
* Pot 8-P0A     -----&amp;gt;       NC&lt;br /&gt;
* Pot 9-P0W    -----&amp;gt;       P0-&lt;br /&gt;
* Pot 10-P0B   -----&amp;gt;       P0+&lt;br /&gt;
* Pot 11 -WP   -----&amp;gt;       NC&lt;br /&gt;
* Pot 12 - SHDN -----&amp;gt;      3.3v&lt;br /&gt;
* Pot 13-SDO  -----&amp;gt;       C4&lt;br /&gt;
* Pot 14-VDD  -----&amp;gt;       3.3v&lt;br /&gt;
&lt;br /&gt;
The resistance across PXB and PXW is what changes, labeled above as Px+ and Px-.&lt;br /&gt;
&lt;br /&gt;
== Library Functions ==&lt;br /&gt;
Code: [[Media:MCP42X1.h|MCP42X1.h]], [[Media:MCP42X1.c|MCP42X1.c]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
MCP42X1.c contains the following functions:&lt;br /&gt;
&lt;br /&gt;
== Sample Code ==&lt;br /&gt;
&lt;br /&gt;
Initialize and clear the LCD:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
  LcdInitialize();&lt;br /&gt;
  LcdClear();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>AndrewKessler</name></author>
	</entry>
	<entry>
		<id>https://hades.mech.northwestern.edu//index.php?title=NU32:_Using_the_MCP42X1_SPI_Digital_Potentiometer&amp;diff=21440</id>
		<title>NU32: Using the MCP42X1 SPI Digital Potentiometer</title>
		<link rel="alternate" type="text/html" href="https://hades.mech.northwestern.edu//index.php?title=NU32:_Using_the_MCP42X1_SPI_Digital_Potentiometer&amp;diff=21440"/>
		<updated>2012-07-14T15:26:28Z</updated>

		<summary type="html">&lt;p&gt;AndrewKessler: /* Sample Code */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
The MCP42X1 is a 7-bit dual digital potentiometer. It is available in total resistance options of 5, 10, 50 and 100 kOhm. It is controlled using SPI communication and a digital output (chip select).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
A potentiometer is useful in a variety of circumstances when a variable resistance is needed. A digital potentiometer allows provides a variable resistor that can be controlled from a microcontroller. Because the MCP42X1 is a 7-bit device, there are 2^7 = 128 possible resistance &amp;quot;steps&amp;quot;. By communicating with the IC over SPI, we can choose what step (and thus, resistance) the potentiometer is set at. &lt;br /&gt;
&lt;br /&gt;
The resistance across the PxB and PxW (the wiper) is governed by&lt;br /&gt;
&amp;lt;math&amp;gt;R_{WB} = \frac{5\Omega;}{128} N&amp;lt;/math&amp;gt;&lt;br /&gt;
where the 5kOhm comes from the total resistance of the pot, depending on the model. The value N is the setting of the pot between 0 and 127. &lt;br /&gt;
&lt;br /&gt;
The pot requires four communication pins from a microcontroller: SPI CLK,  SDO, SDI, and one digital output.  The pot is powered with 3.3V. This model is a dual pot chip, meaning it has two completely independent potentiometer channels in the same IC, referred to as Pot 0 and Pot 1, respectively. &lt;br /&gt;
&lt;br /&gt;
== Details ==&lt;br /&gt;
[[Media:mcp42X1.pdf|Datasheet]]&lt;br /&gt;
&lt;br /&gt;
Example schematic when communicating with the NU32, using SPI channel 1:&lt;br /&gt;
* Pot 1-CS        -----&amp;gt;	   F3&lt;br /&gt;
* Pot 2-SCK      -----&amp;gt;	   D10&lt;br /&gt;
* Pot 3-SDI       -----&amp;gt;	   D0&lt;br /&gt;
* Pot 4-VSS	-----&amp;gt;	   GND&lt;br /&gt;
* Pot 5-P1B	-----&amp;gt;       P1+&lt;br /&gt;
* Pot 6-P1W	-----&amp;gt;       P1-&lt;br /&gt;
* Pot 7-P1A	-----&amp;gt;      NC&lt;br /&gt;
* Pot 8-P0A     -----&amp;gt;       NC&lt;br /&gt;
* Pot 9-P0W    -----&amp;gt;       P0-&lt;br /&gt;
* Pot 10-P0B   -----&amp;gt;       P0+&lt;br /&gt;
* Pot 11 -WP   -----&amp;gt;       NC&lt;br /&gt;
* Pot 12 - SHDN -----&amp;gt;      3.3v&lt;br /&gt;
* Pot 13-SDO  -----&amp;gt;       C4&lt;br /&gt;
* Pot 14-VDD  -----&amp;gt;       3.3v&lt;br /&gt;
&lt;br /&gt;
The resistance across PXB and PXW is what changes, labeled above as Px+ and Px-.&lt;br /&gt;
&lt;br /&gt;
== Library Functions ==&lt;br /&gt;
Code: [[Media:MCP42X1.h|MCP42X1.h]], [[Media:MCP42X1.c|MCP42X1.c]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
MCP42X1.c contains the following functions:&lt;br /&gt;
&lt;br /&gt;
== Sample Code ==&lt;br /&gt;
&lt;br /&gt;
Initialize and clear the LCD:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
  LcdInitialize();&lt;br /&gt;
  LcdClear();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>AndrewKessler</name></author>
	</entry>
	<entry>
		<id>https://hades.mech.northwestern.edu//index.php?title=NU32:_Using_the_MCP42X1_SPI_Digital_Potentiometer&amp;diff=21439</id>
		<title>NU32: Using the MCP42X1 SPI Digital Potentiometer</title>
		<link rel="alternate" type="text/html" href="https://hades.mech.northwestern.edu//index.php?title=NU32:_Using_the_MCP42X1_SPI_Digital_Potentiometer&amp;diff=21439"/>
		<updated>2012-07-14T15:26:14Z</updated>

		<summary type="html">&lt;p&gt;AndrewKessler: /* More Information */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
The MCP42X1 is a 7-bit dual digital potentiometer. It is available in total resistance options of 5, 10, 50 and 100 kOhm. It is controlled using SPI communication and a digital output (chip select).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
A potentiometer is useful in a variety of circumstances when a variable resistance is needed. A digital potentiometer allows provides a variable resistor that can be controlled from a microcontroller. Because the MCP42X1 is a 7-bit device, there are 2^7 = 128 possible resistance &amp;quot;steps&amp;quot;. By communicating with the IC over SPI, we can choose what step (and thus, resistance) the potentiometer is set at. &lt;br /&gt;
&lt;br /&gt;
The resistance across the PxB and PxW (the wiper) is governed by&lt;br /&gt;
&amp;lt;math&amp;gt;R_{WB} = \frac{5\Omega;}{128} N&amp;lt;/math&amp;gt;&lt;br /&gt;
where the 5kOhm comes from the total resistance of the pot, depending on the model. The value N is the setting of the pot between 0 and 127. &lt;br /&gt;
&lt;br /&gt;
The pot requires four communication pins from a microcontroller: SPI CLK,  SDO, SDI, and one digital output.  The pot is powered with 3.3V. This model is a dual pot chip, meaning it has two completely independent potentiometer channels in the same IC, referred to as Pot 0 and Pot 1, respectively. &lt;br /&gt;
&lt;br /&gt;
== Details ==&lt;br /&gt;
[[Media:mcp42X1.pdf|Datasheet]]&lt;br /&gt;
&lt;br /&gt;
Example schematic when communicating with the NU32, using SPI channel 1:&lt;br /&gt;
* Pot 1-CS        -----&amp;gt;	   F3&lt;br /&gt;
* Pot 2-SCK      -----&amp;gt;	   D10&lt;br /&gt;
* Pot 3-SDI       -----&amp;gt;	   D0&lt;br /&gt;
* Pot 4-VSS	-----&amp;gt;	   GND&lt;br /&gt;
* Pot 5-P1B	-----&amp;gt;       P1+&lt;br /&gt;
* Pot 6-P1W	-----&amp;gt;       P1-&lt;br /&gt;
* Pot 7-P1A	-----&amp;gt;      NC&lt;br /&gt;
* Pot 8-P0A     -----&amp;gt;       NC&lt;br /&gt;
* Pot 9-P0W    -----&amp;gt;       P0-&lt;br /&gt;
* Pot 10-P0B   -----&amp;gt;       P0+&lt;br /&gt;
* Pot 11 -WP   -----&amp;gt;       NC&lt;br /&gt;
* Pot 12 - SHDN -----&amp;gt;      3.3v&lt;br /&gt;
* Pot 13-SDO  -----&amp;gt;       C4&lt;br /&gt;
* Pot 14-VDD  -----&amp;gt;       3.3v&lt;br /&gt;
&lt;br /&gt;
The resistance across PXB and PXW is what changes, labeled above as Px+ and Px-.&lt;br /&gt;
&lt;br /&gt;
== Library Functions ==&lt;br /&gt;
Code: [[Media:MCP42X1.h|MCP42X1.h]], [[Media:MCP42X1.c|MCP42X1.c]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
MCP42X1.c contains the following functions:&lt;br /&gt;
&lt;br /&gt;
== Sample Code ==&lt;br /&gt;
&lt;br /&gt;
Initialize and clear the LCD:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
  LcdInitialize();&lt;br /&gt;
  LcdClear();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Go to the leftmost side of the screen on the second line and write &amp;#039;Hello&amp;#039;&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
  gotoXY(0,1);&lt;br /&gt;
  LcdString(&amp;quot;Hello&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Write the value of a variable:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
  char str[5];&lt;br /&gt;
  sprintf(str, &amp;quot;i=%d&amp;quot;, i);&lt;br /&gt;
  LcdString(str);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Turn on a pixel at (20,35):&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
  setPixel(20,35,1);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>AndrewKessler</name></author>
	</entry>
	<entry>
		<id>https://hades.mech.northwestern.edu//index.php?title=NU32:_Using_the_MCP42X1_SPI_Digital_Potentiometer&amp;diff=21438</id>
		<title>NU32: Using the MCP42X1 SPI Digital Potentiometer</title>
		<link rel="alternate" type="text/html" href="https://hades.mech.northwestern.edu//index.php?title=NU32:_Using_the_MCP42X1_SPI_Digital_Potentiometer&amp;diff=21438"/>
		<updated>2012-07-14T15:25:55Z</updated>

		<summary type="html">&lt;p&gt;AndrewKessler: /* Library Functions */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
The MCP42X1 is a 7-bit dual digital potentiometer. It is available in total resistance options of 5, 10, 50 and 100 kOhm. It is controlled using SPI communication and a digital output (chip select).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
A potentiometer is useful in a variety of circumstances when a variable resistance is needed. A digital potentiometer allows provides a variable resistor that can be controlled from a microcontroller. Because the MCP42X1 is a 7-bit device, there are 2^7 = 128 possible resistance &amp;quot;steps&amp;quot;. By communicating with the IC over SPI, we can choose what step (and thus, resistance) the potentiometer is set at. &lt;br /&gt;
&lt;br /&gt;
The resistance across the PxB and PxW (the wiper) is governed by&lt;br /&gt;
&amp;lt;math&amp;gt;R_{WB} = \frac{5\Omega;}{128} N&amp;lt;/math&amp;gt;&lt;br /&gt;
where the 5kOhm comes from the total resistance of the pot, depending on the model. The value N is the setting of the pot between 0 and 127. &lt;br /&gt;
&lt;br /&gt;
The pot requires four communication pins from a microcontroller: SPI CLK,  SDO, SDI, and one digital output.  The pot is powered with 3.3V. This model is a dual pot chip, meaning it has two completely independent potentiometer channels in the same IC, referred to as Pot 0 and Pot 1, respectively. &lt;br /&gt;
&lt;br /&gt;
== Details ==&lt;br /&gt;
[[Media:mcp42X1.pdf|Datasheet]]&lt;br /&gt;
&lt;br /&gt;
Example schematic when communicating with the NU32, using SPI channel 1:&lt;br /&gt;
* Pot 1-CS        -----&amp;gt;	   F3&lt;br /&gt;
* Pot 2-SCK      -----&amp;gt;	   D10&lt;br /&gt;
* Pot 3-SDI       -----&amp;gt;	   D0&lt;br /&gt;
* Pot 4-VSS	-----&amp;gt;	   GND&lt;br /&gt;
* Pot 5-P1B	-----&amp;gt;       P1+&lt;br /&gt;
* Pot 6-P1W	-----&amp;gt;       P1-&lt;br /&gt;
* Pot 7-P1A	-----&amp;gt;      NC&lt;br /&gt;
* Pot 8-P0A     -----&amp;gt;       NC&lt;br /&gt;
* Pot 9-P0W    -----&amp;gt;       P0-&lt;br /&gt;
* Pot 10-P0B   -----&amp;gt;       P0+&lt;br /&gt;
* Pot 11 -WP   -----&amp;gt;       NC&lt;br /&gt;
* Pot 12 - SHDN -----&amp;gt;      3.3v&lt;br /&gt;
* Pot 13-SDO  -----&amp;gt;       C4&lt;br /&gt;
* Pot 14-VDD  -----&amp;gt;       3.3v&lt;br /&gt;
&lt;br /&gt;
The resistance across PXB and PXW is what changes, labeled above as Px+ and Px-.&lt;br /&gt;
&lt;br /&gt;
== Library Functions ==&lt;br /&gt;
Code: [[Media:MCP42X1.h|MCP42X1.h]], [[Media:MCP42X1.c|MCP42X1.c]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
MCP42X1.c contains the following functions:&lt;br /&gt;
&lt;br /&gt;
== Sample Code ==&lt;br /&gt;
&lt;br /&gt;
Initialize and clear the LCD:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
  LcdInitialize();&lt;br /&gt;
  LcdClear();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Go to the leftmost side of the screen on the second line and write &amp;#039;Hello&amp;#039;&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
  gotoXY(0,1);&lt;br /&gt;
  LcdString(&amp;quot;Hello&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Write the value of a variable:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
  char str[5];&lt;br /&gt;
  sprintf(str, &amp;quot;i=%d&amp;quot;, i);&lt;br /&gt;
  LcdString(str);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Turn on a pixel at (20,35):&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
  setPixel(20,35,1);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== More Information ==&lt;br /&gt;
The sample code in [[Media:NU32v2_Nokia5110_example.zip|All example code]] will create the image at the top of this page.  Sending the NU32v2 an &amp;#039;a&amp;#039; over serial will clear the LCD.&lt;/div&gt;</summary>
		<author><name>AndrewKessler</name></author>
	</entry>
	<entry>
		<id>https://hades.mech.northwestern.edu//index.php?title=NU32:_Using_the_MCP42X1_SPI_Digital_Potentiometer&amp;diff=21437</id>
		<title>NU32: Using the MCP42X1 SPI Digital Potentiometer</title>
		<link rel="alternate" type="text/html" href="https://hades.mech.northwestern.edu//index.php?title=NU32:_Using_the_MCP42X1_SPI_Digital_Potentiometer&amp;diff=21437"/>
		<updated>2012-07-14T15:23:34Z</updated>

		<summary type="html">&lt;p&gt;AndrewKessler: Created page with &amp;quot; The MCP42X1 is a 7-bit dual digital potentiometer. It is available in total resistance options of 5, 10, 50 and 100 kOhm. It is controlled using SPI communication and a digit...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
The MCP42X1 is a 7-bit dual digital potentiometer. It is available in total resistance options of 5, 10, 50 and 100 kOhm. It is controlled using SPI communication and a digital output (chip select).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
A potentiometer is useful in a variety of circumstances when a variable resistance is needed. A digital potentiometer allows provides a variable resistor that can be controlled from a microcontroller. Because the MCP42X1 is a 7-bit device, there are 2^7 = 128 possible resistance &amp;quot;steps&amp;quot;. By communicating with the IC over SPI, we can choose what step (and thus, resistance) the potentiometer is set at. &lt;br /&gt;
&lt;br /&gt;
The resistance across the PxB and PxW (the wiper) is governed by&lt;br /&gt;
&amp;lt;math&amp;gt;R_{WB} = \frac{5\Omega;}{128} N&amp;lt;/math&amp;gt;&lt;br /&gt;
where the 5kOhm comes from the total resistance of the pot, depending on the model. The value N is the setting of the pot between 0 and 127. &lt;br /&gt;
&lt;br /&gt;
The pot requires four communication pins from a microcontroller: SPI CLK,  SDO, SDI, and one digital output.  The pot is powered with 3.3V. This model is a dual pot chip, meaning it has two completely independent potentiometer channels in the same IC, referred to as Pot 0 and Pot 1, respectively. &lt;br /&gt;
&lt;br /&gt;
== Details ==&lt;br /&gt;
[[Media:mcp42X1.pdf|Datasheet]]&lt;br /&gt;
&lt;br /&gt;
Example schematic when communicating with the NU32, using SPI channel 1:&lt;br /&gt;
* Pot 1-CS        -----&amp;gt;	   F3&lt;br /&gt;
* Pot 2-SCK      -----&amp;gt;	   D10&lt;br /&gt;
* Pot 3-SDI       -----&amp;gt;	   D0&lt;br /&gt;
* Pot 4-VSS	-----&amp;gt;	   GND&lt;br /&gt;
* Pot 5-P1B	-----&amp;gt;       P1+&lt;br /&gt;
* Pot 6-P1W	-----&amp;gt;       P1-&lt;br /&gt;
* Pot 7-P1A	-----&amp;gt;      NC&lt;br /&gt;
* Pot 8-P0A     -----&amp;gt;       NC&lt;br /&gt;
* Pot 9-P0W    -----&amp;gt;       P0-&lt;br /&gt;
* Pot 10-P0B   -----&amp;gt;       P0+&lt;br /&gt;
* Pot 11 -WP   -----&amp;gt;       NC&lt;br /&gt;
* Pot 12 - SHDN -----&amp;gt;      3.3v&lt;br /&gt;
* Pot 13-SDO  -----&amp;gt;       C4&lt;br /&gt;
* Pot 14-VDD  -----&amp;gt;       3.3v&lt;br /&gt;
&lt;br /&gt;
The resistance across PXB and PXW is what changes, labeled above as Px+ and Px-.&lt;br /&gt;
&lt;br /&gt;
== Library Functions ==&lt;br /&gt;
Code: [[Media:Nokia5110.h|Nokia5110.h]], [[Media:Nokia5110.c|Nokia5110.c]]&lt;br /&gt;
&lt;br /&gt;
Full example: [[Media:NU32v2_Nokia5110_example.zip|All example code]]&lt;br /&gt;
&lt;br /&gt;
Nokia5110.h sets up control pins on E0, E1 and E2. These may be changed if desired.  The file also contains function prototypes, constants, and a 96 x 5 element lookup array of ASCII characters.&lt;br /&gt;
&lt;br /&gt;
Nokia5110.c contains the following functions:&lt;br /&gt;
* LcdCharacter - used to write an individual ASCII character&lt;br /&gt;
* LcdClear - clears the entire LCD&lt;br /&gt;
* LcdInitialize - Initializes SPI3 (can be changed if desired) and sends the startup commands to the LCD&lt;br /&gt;
** The second command sent (LCD Vop) sets the contrast of the LCD and can be altered for more or less contrast&lt;br /&gt;
* LcdString - writes a string of characters to the LCD&lt;br /&gt;
* LcdWrite - sends individual commands to the LCD&lt;br /&gt;
** Sending commands before the LCD is ready for them will make the LCD miss them, so 1000 Nop()s are called between commands&lt;br /&gt;
* gotoXY - places the cursor at an x pixel (0-84) and y character (0-5)&lt;br /&gt;
* setPixel - turns on a pixel at x (0-84) and y (0-48)&lt;br /&gt;
&lt;br /&gt;
== Sample Code ==&lt;br /&gt;
&lt;br /&gt;
Initialize and clear the LCD:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
  LcdInitialize();&lt;br /&gt;
  LcdClear();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Go to the leftmost side of the screen on the second line and write &amp;#039;Hello&amp;#039;&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
  gotoXY(0,1);&lt;br /&gt;
  LcdString(&amp;quot;Hello&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Write the value of a variable:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
  char str[5];&lt;br /&gt;
  sprintf(str, &amp;quot;i=%d&amp;quot;, i);&lt;br /&gt;
  LcdString(str);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Turn on a pixel at (20,35):&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
  setPixel(20,35,1);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== More Information ==&lt;br /&gt;
The sample code in [[Media:NU32v2_Nokia5110_example.zip|All example code]] will create the image at the top of this page.  Sending the NU32v2 an &amp;#039;a&amp;#039; over serial will clear the LCD.&lt;/div&gt;</summary>
		<author><name>AndrewKessler</name></author>
	</entry>
	<entry>
		<id>https://hades.mech.northwestern.edu//index.php?title=Microchip_PICs&amp;diff=21370</id>
		<title>Microchip PICs</title>
		<link rel="alternate" type="text/html" href="https://hades.mech.northwestern.edu//index.php?title=Microchip_PICs&amp;diff=21370"/>
		<updated>2012-05-28T02:01:58Z</updated>

		<summary type="html">&lt;p&gt;AndrewKessler: /* Using the NU32 (Winter 2012 and on) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;#039;&amp;#039;&amp;#039;Note:  Some of the code on the bottom of this page was written using the CCS compiler.  All new code is being written using Microchip&amp;#039;s MPLAB X.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;[http://peshkin.mech.northwestern.edu/pic/code Link to all PIC18F sample code here.]&amp;lt;/b&amp;gt;&lt;br /&gt;
*[[Sample code for most PIC18F4520 operations]]&lt;br /&gt;
*[http://www.ccsinfo.com/forum/ CCS user forum]&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
__TOC__&lt;br /&gt;
== The NUScope ==&lt;br /&gt;
*[[NUScope]]&lt;br /&gt;
== Using the NU32 (Winter 2012 and on) ==&lt;br /&gt;
*[[NU32: Introduction to the PIC32]]&lt;br /&gt;
**[[NU32: What is in the NU32 Kit]]&lt;br /&gt;
**[[NU32: Software to Install]]&lt;br /&gt;
**[[NU32: Starting a New Project and Putting it on the NU32]]&lt;br /&gt;
**[[NU32: A Detailed Look at Programming the PIC32 on the NU32]]&lt;br /&gt;
* Sample Code&lt;br /&gt;
**[[NU32: Serial Communication with the PC]]&lt;br /&gt;
**[[NU32: 16x2 LCD]]&lt;br /&gt;
**[[NU32: Digital Input and Output]]&lt;br /&gt;
**[[NU32: Counters and Timers]]&lt;br /&gt;
**[[NU32: Interrupts]]&lt;br /&gt;
**[[NU32: Output Compare, PWM, and Analog Output]]&lt;br /&gt;
**[[NU32: Analog Input]]&lt;br /&gt;
**[[NU32: Using the dsPIC33FJ12MC201 QEI to SPI board]]&lt;br /&gt;
**[[NU32: Using the MAX9918 current sensor]]&lt;br /&gt;
**[[NU32: Using the TB6612 H-Bridge]]&lt;br /&gt;
**[[NU32: Driving RC servo motors]]&lt;br /&gt;
**[[NU32: Driving a stepper motor]]&lt;br /&gt;
**[[NU32: Using the LS7183 Quadrature Clock Converter]]&lt;br /&gt;
**[[NU32: Using the L293D H-Bridge]]&lt;br /&gt;
**[[NU32: Digital Signal Processing]]&lt;br /&gt;
**[[NU32: Input Capture]]&lt;br /&gt;
**[[NU32: Flash Self-Programming]]&lt;br /&gt;
**[[NU32: UART Asynchronous Serial Communication]]&lt;br /&gt;
**[[NU32: I2C Synchronous Serial Communication]]&lt;br /&gt;
**[[NU32: SPI Synchronous Serial Communication]]&lt;br /&gt;
**[[NU32: Watchdog Timer]]&lt;br /&gt;
**[[NU32: VC0706 Serial Camera]]&lt;br /&gt;
&lt;br /&gt;
== Using the NU32v2 (Winter 2011) ==&lt;br /&gt;
*[[NU32v2: Introduction to the PIC32]]&lt;br /&gt;
**[[NU32v2: What is in the NU32v2 Kit]]&lt;br /&gt;
**[[NU32v2: Software to Install]]&lt;br /&gt;
**[[NU32v2: Starting a New Project and Putting it on the NU32v2]]&lt;br /&gt;
**[[NU32v2: Using the Simulator]]&lt;br /&gt;
**[[NU32v2: A Detailed Look at Programming the PIC32]]&lt;br /&gt;
**[[NU32v2: Benchmark Test]]&lt;br /&gt;
* Sample Code&lt;br /&gt;
**[[NU32v2: Digital Input and Output]]&lt;br /&gt;
**[[NU32v2: Counters and Timers]]&lt;br /&gt;
**[[NU32v2: Interrupts]]&lt;br /&gt;
**[[NU32v2: Output Compare, PWM, and Analog Output]]&lt;br /&gt;
**[[NU32v2: Serial Communication with the PC]]&lt;br /&gt;
**[[NU32v2: Nokia 5110 LCD]]&lt;br /&gt;
**[[NU32v2: Analog Input]]&lt;br /&gt;
**[[NU32v2: Using the LS7183 Quadrature Clock Converter]]&lt;br /&gt;
**[[NU32v2: Using the L293D H-Bridge]]&lt;br /&gt;
**[[NU32v2: Input Capture]]&lt;br /&gt;
**[[NU32v2: Flash Self-Programming]]&lt;br /&gt;
**[[NU32v2: UART Asynchronous Serial Communication]]&lt;br /&gt;
**[[NU32v2: I2C Synchronous Serial Communication]]&lt;br /&gt;
**[[NU32v2: SPI Synchronous Serial Communication]]&lt;br /&gt;
**[[NU32v2: Digital Signal Processing]]&lt;br /&gt;
**[[NU32v2: Watchdog Timer]]&lt;br /&gt;
**[[NU32v2: Simple Analog Input]]&lt;br /&gt;
&lt;br /&gt;
== Using the PIC18F4520 ==&lt;br /&gt;
*[[4520 Board intro]]&lt;br /&gt;
*[[4520 Board construction]]&lt;br /&gt;
*[[4520 Board use]]&lt;br /&gt;
*[[Microcontroller PIC18F4520]]&lt;br /&gt;
*[[PIC MCUs: Capabilities of PIC18F4520]]&lt;br /&gt;
**[[PIC18F4520: PWM Motor Control]]&lt;br /&gt;
**[[PIC18F4520: Digital Outputs]]&lt;br /&gt;
**[[PIC18F4520: Digital Inputs]]&lt;br /&gt;
**[[PIC18F4520: Serial Digital-to-Analog Conversion]]&lt;br /&gt;
**[[PIC18F4520: Analog Inputs]]&lt;br /&gt;
**[[PIC18F4520: Timers]]&lt;br /&gt;
**[[PIC18F4520: Comparator]]&lt;br /&gt;
&lt;br /&gt;
== Example Code in C for PIC18F4520==&lt;br /&gt;
*[[C Example: Parallel Interfacing with LCDs]]&lt;br /&gt;
*[[C Example: Digital Inputs]]&lt;br /&gt;
*[[C Example: PWM Motor Control]]&lt;br /&gt;
*[[C Example: Comparators]]&lt;br /&gt;
*[[C Example: Digital Outputs]]&lt;br /&gt;
*[[C Example: Analog Inputs]]&lt;br /&gt;
*[[C Example: Digital Outputs (Ports)]]&lt;br /&gt;
*[[C Example: Bi-Directional PWM Motor Control]]&lt;br /&gt;
*[[C Example: Serial LCD]]&lt;br /&gt;
&lt;br /&gt;
== Using the PIC32MX Series ==&lt;br /&gt;
*[[Introduction to the PIC32]]&lt;br /&gt;
*[[Getting Started with PIC32]] (includes NU32 development board)&lt;br /&gt;
** Download PIC32 Tutorial Files [[Media: PIC32_TutorialFiles.zip|here]].&lt;br /&gt;
** [[ME 333 Lab 2]] - Includes Digital IO, Analog Input, Parallel LCD and RS232 Com&lt;br /&gt;
** [[ME 333 Lab 4]] - Includes PWM and Encoder Motor Control&lt;br /&gt;
*[[Microcontroller PIC32MX460F512L]]&lt;br /&gt;
*[[Programming HID Bootloader on PIC32]] &lt;br /&gt;
*[[HelloWorld PIC32|Directions to code HelloWorld]]&lt;br /&gt;
*[[Directions to Load Files to PIC32 with HID Bootloader]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*[[PIC MCUs: Capabilities of PIC32MX]]&lt;br /&gt;
**[[Programming HID Bootloader on PIC32 |PIC32MX: Bootloader]]&lt;br /&gt;
**Simple Programs&lt;br /&gt;
***[[PIC32MX: Digital Inputs]]&lt;br /&gt;
***[[PIC32MX: Digital Outputs]]&lt;br /&gt;
***[[PIC32MX: Analog Inputs]]&lt;br /&gt;
**Communication&lt;br /&gt;
***[[PIC32MX: Parallel LCD]]&lt;br /&gt;
***[[PIC32MX: RS232]]&lt;br /&gt;
***[[PIC32MX:  USB Communication with a PC]]&lt;br /&gt;
***[[PIC32MX:  SPI External RAM]]&lt;br /&gt;
***[[PIC32MX:  I2C DAC]]&lt;br /&gt;
***[[PIC32MX:  I2C EEPROM]]&lt;br /&gt;
***[[PIC32MX:  SPI EEPROM]]&lt;br /&gt;
***[[PIC32MX:  I2C Communication between PIC32s]]&lt;br /&gt;
***[[PIC32MX:  SPI Communication between PIC32s]]&lt;br /&gt;
**Motor Control&lt;br /&gt;
***[[PIC32MX: PWM Motor Control|PIC32MX: PWM Motor Control]]&lt;br /&gt;
***[[PIC32MX: Encoder Motor Control|PIC32MX: Encoder Motor Control]]&lt;br /&gt;
***[[PIC32MX: Servo Control|PIC32MX: Servo Control]]&lt;br /&gt;
***[[PIC32MX:  Driving a Stepper Motor]]&lt;br /&gt;
***[[Using the LS7166 Quadrature Counter]]&lt;br /&gt;
***[[Using the LS7366R SPI Quadrature Counter]]&lt;br /&gt;
**Capabilities&lt;br /&gt;
***[[PIC32MX:  Benchmarking Mathematical Operations]]&lt;br /&gt;
***[[PIC32MX:  FFT of Analog Input]]&lt;br /&gt;
***[[PIC32MX:  Sinusoidal Analog Output]]&lt;br /&gt;
***[[PIC32MX:  XBee Wireless Round-trip Latency]]&lt;br /&gt;
***[[PIC32MX:  Interfacing with Force Sensors from a Scale]]&lt;br /&gt;
***[[PIC32MX:  Storing Data in Flash Memory (Run-Time Self Programming)]]&lt;br /&gt;
&lt;br /&gt;
==Other PIC Resources ==&lt;br /&gt;
&lt;br /&gt;
*[[PIC PWM Motor Driver]]&lt;br /&gt;
*[[Writing Code with the C18 Compiler]]&lt;br /&gt;
*[[Controlling a seven segment display]]&lt;br /&gt;
*[[PIC Microcontrollers with C18 Compiler]]&lt;br /&gt;
*[[PIC Motor Control and Serial Port Example]]&lt;br /&gt;
*[[PIC16F684]]&lt;br /&gt;
*[[PIC Microcontrollers with CCS Compiler]]&lt;br /&gt;
*[[Stepper motor control with the PIC]]&lt;br /&gt;
*[[PIC/C18 Compiler Tips and Troubleshooting]]&lt;br /&gt;
*[[CCS C]]&lt;br /&gt;
*[[Analog Input]]&lt;br /&gt;
*[[PIC MCUs: Hardware and Connections]]&lt;br /&gt;
*[[Storing constant data in program memory]]&lt;br /&gt;
*[[PIC Analog-Digital-Converter Example]]&lt;br /&gt;
*[[PIC Microcontroller]]&lt;br /&gt;
*[[Digital inputs &amp;amp; outputs]]&lt;br /&gt;
*[[Debugging C on a PIC]]&lt;br /&gt;
*[[Analog Output]]&lt;br /&gt;
*[[PIC MCUs: Software]]&lt;br /&gt;
*[[Interfacing to External EEPROM]]&lt;br /&gt;
*[[CCS IDE]]&lt;br /&gt;
*[[Interrupts]]&lt;br /&gt;
*[[PIC16F684 Registers]]&lt;br /&gt;
*[[Waveform Generation with AD9833]]&lt;br /&gt;
*[[Waveform Generation with AD9833, and SPI]]&lt;br /&gt;
*[[PIC computation time benchmarks]]&lt;br /&gt;
*[[PICkit 1]]&lt;br /&gt;
*[[PIC MCUs: 4520 Board]]&lt;br /&gt;
*[[More debugging tips]]&lt;br /&gt;
*[[Example Writeup: Analog Input]]&lt;br /&gt;
*[[LED Drivers]]&lt;br /&gt;
*[[Embedded Programming Tips for CCS C]]&lt;br /&gt;
*[[Wireless PIC bootloading]]&lt;br /&gt;
*[[PIC 18f4553]]&lt;br /&gt;
*[[I2C Motor Controller]]&lt;br /&gt;
*[[Driving a piezo speaker with a PIC]]&lt;br /&gt;
*[[PIC Servo Controller]]&lt;br /&gt;
*[[Watchdog timer]]&lt;br /&gt;
*[[Interfacing PIC with SPI memory]]&lt;br /&gt;
*[[Using the LS7166 Quadrature Counter]]&lt;br /&gt;
&lt;br /&gt;
==Programming the PIC with Microchip&amp;#039;s MPLAB==&lt;/div&gt;</summary>
		<author><name>AndrewKessler</name></author>
	</entry>
	<entry>
		<id>https://hades.mech.northwestern.edu//index.php?title=NU32:_VC0706_Serial_Camera&amp;diff=21369</id>
		<title>NU32: VC0706 Serial Camera</title>
		<link rel="alternate" type="text/html" href="https://hades.mech.northwestern.edu//index.php?title=NU32:_VC0706_Serial_Camera&amp;diff=21369"/>
		<updated>2012-05-22T22:17:56Z</updated>

		<summary type="html">&lt;p&gt;AndrewKessler: Created page with &amp;quot;  =Using the VC0706 Serial Camera Module=  The VC0706 is a video module originally designed for surveillance purposes. It can be used to stream analog NTSC video to a monitor,...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
&lt;br /&gt;
=Using the VC0706 Serial Camera Module=&lt;br /&gt;
&lt;br /&gt;
The VC0706 is a video module originally designed for surveillance purposes. It can be used to stream analog NTSC video to a monitor, or to take a snapshot and spit it out as a JPEG over a serial connection. It also has built in motion detection features. The camera can take pictures at 640x480, 320x240, or 160x200. Since using the module to stream video over an RCA connection is trivial, this tutorial will focus on retrieving snapshots.&lt;br /&gt;
&lt;br /&gt;
Since the VC0706 is its own self-contained serial module, you could just connect the camera directly to a PC using an RS232 cable, and interact with it using some terminal software. A Python script is available to directly interface with the camera over serial. The VC0706 uses 3.3V TTL logic, so if you use a 5V RS232-USB cable, make sure you step down the voltage coming out of the computer using a voltage divider, to avoid frying the camera.&lt;br /&gt;
This tutorial focuses on how to interact with the module from the perspective of a PIC32 microcontroller.&lt;br /&gt;
&lt;br /&gt;
==Wiring==&lt;br /&gt;
Simply connect the TX and RX pins on the VC0706 to any UART port on the NU32. I used UART2, which uses pins F4 and F5. Make sure you connect the camera’s TX to the PIC’s RX, and visa versa1. Also, connect VCC to 5V and GND to the PIC’s GND.&lt;br /&gt;
&lt;br /&gt;
==Open a UART port==&lt;br /&gt;
&lt;br /&gt;
The default baud is 38400. You can change the default baud rate in code once you have established communication. &lt;br /&gt;
&lt;br /&gt;
==Taking a picture==&lt;br /&gt;
The basic flow of events is as follows: freeze the image buffer on the VC0706, transfer data from VC0706 to PIC, thaw image buffer, repeat.&lt;br /&gt;
&lt;br /&gt;
If you don’t thaw the buffer after freezing it, freezing the buffer and transferring data from the buffer will just keep giving you the same picture!&lt;br /&gt;
&lt;br /&gt;
==After you have a picture==&lt;br /&gt;
After the picture is on the PIC in some kind of buffer, you can do whatever you want with it. Write it to an SD card, spit it out over serial, whatever (if you choose this route, set your terminal app to record serial output to a text file, then just rename it as a .jpg).&lt;br /&gt;
If you were planning on doing some kind of image processing onboard the PIC, then I’ve got&lt;br /&gt;
some bad news for you. The camera exports pictures as compressed JPEGs, meaning that the color values of each pixel (which you would want access to to analyze the image) are heavily compressed and encrypted. It is possible to decompress the JPEG to a bitmap, but the trouble is finding code to do that efficiently on an embedded platform. It would also probably be a time-consuming procedure onboard the PIC, meaning it would be difficult to use it for any sort of real-time application. But you’re welcome to try!&lt;br /&gt;
&lt;br /&gt;
==Issues==&lt;br /&gt;
Make sure you handle incoming serial transmissions from the VC0706 in an interrupt with a very large incoming buffer, because the built in UART buffer (about 8 bytes) will quickly be overwhelmed from the camera if you’re polling instead.&lt;br /&gt;
You can always make sure your camera is working by hooking it up directly to the PC using an RS232 cable, and using a Windows utility to interact with it.&lt;/div&gt;</summary>
		<author><name>AndrewKessler</name></author>
	</entry>
	<entry>
		<id>https://hades.mech.northwestern.edu//index.php?title=PIC32MX:_High-speed_Wireless_Communication&amp;diff=19040</id>
		<title>PIC32MX: High-speed Wireless Communication</title>
		<link rel="alternate" type="text/html" href="https://hades.mech.northwestern.edu//index.php?title=PIC32MX:_High-speed_Wireless_Communication&amp;diff=19040"/>
		<updated>2010-09-17T16:10:12Z</updated>

		<summary type="html">&lt;p&gt;AndrewKessler: /* Latency and Data Rates */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Overview ==&lt;br /&gt;
&lt;br /&gt;
[[Image:nrf-pic1.jpg|thumb|nrf24L01+ wireless chip with pins attatched]]&lt;br /&gt;
This wiki describes how to wire a [http://www.sparkfun.com/commerce/product_info.php?products_id=691 nRF24L01+ chip] (&amp;quot;wireless chip&amp;quot;) to a PIC32 board and includes annotated code describing the functions that facilitate the transmitting and receiving of wireless data. A  [[media:Wireless-ppt.pdf|PowerPoint presentation]] covering much of the introductory information available on this page is also available. &lt;br /&gt;
&lt;br /&gt;
To operate the system, you must properly connect the wireless chips to the PIC32s, load the transmitter code onto the PIC that you wish to act as a transmitter, load the receiver code onto the PIC that you wish to act as a receiver, properly connect an RS232 cable to the PIC and open a serial communication program (e.g. HyperTerminal or [http://chiark.greenend.org.uk/~sgtatham/putty/download.html putty]), and turn the NU32 boards on. If you use the c-files provided on this pages (and everything else is set up properly), the transmitting PIC will broadcast  any characters received from the PC via RS232, and the receiving PIC will display what it receives from wireless link on the PC via RS232. The payload width can be adjusted using the &amp;quot;[&amp;quot; and &amp;quot;]&amp;quot; keys on both the transmitting and receiving PICs. Both wireless chips must be set to the same payload width in order to communicate. Payload widths may vary from 1 to 32. The transmitting PIC will not transmit until enough characters have been entered to fill a payload. Once enough characters have been entered into the transmitting PIC, the serial display will move to a new line to signal transmission.&lt;br /&gt;
&lt;br /&gt;
==Chip Basics==&lt;br /&gt;
The nrf24L01+ Module is a breakout of the nrf24L01+ 2.4 GHz transceiver, with an on board antenna. In order to get a wireless link up and running, the following parameters must be consistent between a transmitter and receiver chip:&lt;br /&gt;
&lt;br /&gt;
===Channels===&lt;br /&gt;
The channel of the nrf24L01+ chip is the frequency that it broadcasts and receives data from. The channel can range from 2.4 GHz to 2.525 GHz, at intervals no more than 1 MHz. The exact distance between channels is dependent on the on air data rate. Two wireless chips must be tuned to the same channel in order to communicate.  See the Air Data Rate section for necessary channel spacing.&lt;br /&gt;
&lt;br /&gt;
===Air Data Rate===&lt;br /&gt;
The air data rate is the rate at which the chip transmits bits wirelessly (and the rate at which it looks for them). The nrf24L01+ chip has three selectable data rates: 250 kbps, 1 Mbps, and 2 Mbps. Faster data rates draw less current, but require a greater distance between channels. Slower data rates give you the option of more channels and better receiver sensitivity, for the obvious trade off of speed. Data rates of 250 kbps and 1 Mbps require channel spacing of at least 1 MHz (allowing for 125 unique channels), and a data rate of 2 Mbps requires spacing of 2 MHz between channels (allowing for 62 channels).  Two wireless chips will not be able to communicate if they are not set to the same on air data rate.&lt;br /&gt;
&lt;br /&gt;
===Payload Width===&lt;br /&gt;
The payload is the actual data you are trying to send over a wireless link, and the payload width is how many bytes are contained within each payload. The nfr24L01+ is capable of supporting payloads up to 32 bytes. A transmitter and receiver must be set to the same payload in order to communicate. Transmission speeds for different sizes payloads are analyzed below. &lt;br /&gt;
&lt;br /&gt;
===Addresses &amp;amp; Pipes===&lt;br /&gt;
Every wireless transmission is preceded by the address of the intended receiver. The nrf24L01+ chip has 6 different receiving pipes, which means it may act as 6 receivers with 6 different addresses. Addresses may be three, four, or five bytes long. The addresses for pipe 0 and 1 may be completely different, but the addresses for pipes 2, 3, and 4 may only differ from the address of pipe 1 by their least significant byte. All active pipes feed into the same 3-packet-deep  incoming transmission queue.  Each pipe may also be set to a expect a different payload width.&lt;br /&gt;
&lt;br /&gt;
== Circuit ==&lt;br /&gt;
&lt;br /&gt;
[[Image:Wireless-circuit.jpg|thumb|Schematic of the nRF24L01+ connected to the PIC32_NU32 board]]&lt;br /&gt;
&lt;br /&gt;
The nrf24L01+ chip has 8 pins that need to be wired to the PIC (all I/O are relative to PIC):&lt;br /&gt;
&lt;br /&gt;
*Vcc: +3.3 Vdc supply&amp;lt;br&amp;gt;&lt;br /&gt;
*CE:  uC pin C1 (input)&amp;lt;br&amp;gt;&lt;br /&gt;
*CSN: uC pin C2 (output) &amp;lt;br&amp;gt;&lt;br /&gt;
*SCK: uC pin D10, configured as SCK(SPI) (output)&amp;lt;br&amp;gt;&lt;br /&gt;
*MOSI: uC pin D0, configured as SDO(SPI) (output) &amp;lt;br&amp;gt;&lt;br /&gt;
*MISO: uC pin C4, configured as SDI(SPI) (input)&amp;lt;br&amp;gt;&lt;br /&gt;
*IRQ: uC pin B0 (input) &amp;lt;br&amp;gt;&lt;br /&gt;
*GND: common digital ground&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The +3.3V and ground are provided by the NU32 board. The term &amp;quot;uC&amp;quot; above stands for microcontroller, which is the PIC32 in our case. &lt;br /&gt;
&lt;br /&gt;
Descriptions of the wireless chip&amp;#039;s pins can be found in Brennan Ball&amp;#039;s DIYembedded [http://www.diyembedded.com/tutorials/nrf24l01_0/nrf24l01_tutorial_0.pdf Tutorial 0]. The SCK, MOSI, and MISO pins interface with the SPI on the PIC32 which allows for communication between the PIC and the wireless chip. The GPIO pins will be initialized as digital inputs or outputs in the code to enable/disable the wireless chip and check the wireless data transfer/receive stats.&lt;br /&gt;
&lt;br /&gt;
In order to print information from the PIC to the PC, we need to wire an [[PIC_RS232]] cable&amp;#039;s transfer and receive lines to the UART ports of the NU32 board (F4, F5).&lt;br /&gt;
&lt;br /&gt;
==Code==&lt;br /&gt;
&lt;br /&gt;
===Driver===&lt;br /&gt;
Besides the main C files for the transmitter and receiver, the project also needs the [[media:Wireless-files.zip|nRF24L01.h header file and C file]]. These driver files were created by Brennan Ball, and are explained in detail in his [http://blog.diyembedded.com/ tutorials]. The following things must be changed in the header file available on his website to make it compatible with the NU32 board:&lt;br /&gt;
*pin registers and masks must be set to the appropriate values&lt;br /&gt;
*the &amp;quot;HardwareProfile.h&amp;quot; NU32 specific file must be included &lt;br /&gt;
&lt;br /&gt;
These changes are accounted for the the driver available on this page. All of the SPI functions trace back to a single function to send and read a single byte, which must be defined in the main c file. &lt;br /&gt;
&lt;br /&gt;
This function is available here: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 unsigned char spi_send_read_byte(unsigned char byte) {&lt;br /&gt;
  	 unsigned short	txData, rxData; // transmit, receive characters&lt;br /&gt;
   	 int chn = 1; // SPI channel to use (1 or 2)&lt;br /&gt;
  	 &lt;br /&gt;
   	 txData = byte; // take inputted byte and store into txData   &lt;br /&gt;
   	 SpiChnPutC(chn, txData);			// send data&lt;br /&gt;
 	 rxData = SpiChnGetC(chn);			// retreive over channel chn the received data into rxData&lt;br /&gt;
    &lt;br /&gt;
  	 return rxData; &lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
===Initialization Functions===&lt;br /&gt;
In order to get a wireless link up and running, you will need to initialize both the wireless chip and SPI communication on the PIC. &lt;br /&gt;
To intialize SPI on the PIC, create the following function in your main C file:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;void SpiInitDevice(int chn, int isMaster, int frmEn, int frmMaster) {&lt;br /&gt;
   	 unsigned int config = SPI_CON_MODE8|SPI_CON_SMP|SPI_CON_ON;	// SPI configuration word&lt;br /&gt;
   	 if(isMaster)&lt;br /&gt;
   	 {&lt;br /&gt;
   		 config|=SPI_CON_MSTEN;&lt;br /&gt;
   	 }&lt;br /&gt;
   	 if(frmEn)&lt;br /&gt;
   	 {&lt;br /&gt;
   		 config|=SPI_CON_FRMEN;&lt;br /&gt;
   		 if(!frmMaster) {   &lt;br /&gt;
   			 config|=SPI_CON_FRMSYNC;&lt;br /&gt;
      	 }&lt;br /&gt;
   	 }&lt;br /&gt;
  	 SpiChnOpen(chn, config, 4);	// divide fpb by 4, configure the I/O ports. Not using SS in this example&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
You can then call this function with the call &amp;lt;code&amp;gt; SpiInitDevice(1,1,0,0) &amp;lt;/code&amp;gt; to initalize SPI channel 1 on the PIC. &lt;br /&gt;
&lt;br /&gt;
To initialize the nrf24L01+ chip itself, you have to options. You can either use &amp;lt;code&amp;gt; nrf24L01_initialize(..) &amp;lt;/code&amp;gt; which gives  you the opportunity to manually define every register in the chip right from the start. However, this function has 21 arguments, so it is not the most convenient to use if you don&amp;#039;t have to. Instead, you can use &amp;lt;code&amp;gt; nrf24L01_initialize_debug(bool rx, int width, bool auto_ack_on) &amp;lt;/code&amp;gt;, which gives you the option to specify whether or not the chip is a receiver or transmitter, what the payload width is, and whether or not to enable auto-acknowledge. However, it limits you to Pipe 0, an air data rate of 2 Mpbs, and RF Channel 2. However, these limitations can be adjusted easily after initialization using additional functions (see the library for all available functions). So, for example, to initialize your chip as a transmitter with a payload width of one byte and no auto-acknowledgement, you could call &amp;lt;code&amp;gt; nrf24L01_initialize_debug(0,1,0)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If you wish to display information to the screen or receive information from the keyboard, you will have to initialize the RS232 connection as well. This can be done with the following code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
int pbClk = SYSTEMConfigPerformance(SYS_FREQ);&lt;br /&gt;
initUART2(pbClk);&lt;br /&gt;
&lt;br /&gt;
 void initUART2(int pbClk) {&lt;br /&gt;
  	 #define config1 	UART_EN | UART_IDLE_CON | UART_RX_TX | UART_DIS_WAKE | UART_DIS_LOOPBACK | UART_DIS_ABAUD | UART_NO_PAR_8BIT | UART_1STOPBIT | UART_IRDA_DIS | UART_DIS_BCLK_CTS_RTS| UART_NORMAL_RX | UART_BRGH_SIXTEEN&lt;br /&gt;
  	 #define config2		UART_TX_PIN_LOW | UART_RX_ENABLE | UART_TX_ENABLE | UART_INT_TX | UART_INT_RX_CHAR | UART_ADR_DETECT_DIS | UART_RX_OVERRUN_CLEAR	&lt;br /&gt;
   	 OpenUART2( config1, config2, pbClk/16/DESIRED_BAUDRATE-1);	// calculate actual BAUD generate value.&lt;br /&gt;
   	 ConfigIntUART2(UART_INT_PR2 | UART_RX_INT_EN);&lt;br /&gt;
   	 //INTEnableSystemMultiVectoredInt(); //interrupts enabled?&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Transmitter Code===&lt;br /&gt;
&lt;br /&gt;
Wirelessly transmitting data requires three steps:&lt;br /&gt;
&lt;br /&gt;
*initialize nrf24L01+ as transmitter&lt;br /&gt;
*transmit packet&lt;br /&gt;
*wait for payload to be sent&lt;br /&gt;
&lt;br /&gt;
A basic outline for such a procedure would look like:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
char data = &amp;#039;x&amp;#039;; //data to send&lt;br /&gt;
int width = 1; //width of payload&lt;br /&gt;
&lt;br /&gt;
nrf24l01_initialize_debug(false, width, false); //initialize the 24L01 to the debug configuration as TX, 1  data byte, and auto-ack disabled&lt;br /&gt;
&lt;br /&gt;
nrf24l01_write_tx_payload(&amp;amp;data, width, true); //add char to Tx queue, and transmit immediately  (char * data, int width, bool transmit_now)&lt;br /&gt;
&lt;br /&gt;
while(!(nrf24l01_irq_pin_active() &amp;amp;&amp;amp; nrf24l01_irq_tx_ds_active())); //wait until IRQ status tells us that it is done transmitting&lt;br /&gt;
&lt;br /&gt;
nrf24l01_irq_clear_all(); //clear all interrupts in the 24L01&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A fully functional [[media:nrf-tx.c|transmitter c-file]] is available. It is intended to work with the receiving code file, available below, and allows for a variable payload.&lt;br /&gt;
&lt;br /&gt;
===Receiver Code===&lt;br /&gt;
Similarly, receiving data from a wireless link requires three steps:&lt;br /&gt;
*initialize nrf24L01+ as receiver&lt;br /&gt;
*wait for incoming packet&lt;br /&gt;
*write packet to memory&lt;br /&gt;
&lt;br /&gt;
That would look like: &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
char data; //variable to recieve incoming data&lt;br /&gt;
int width = 1; //width of payload&lt;br /&gt;
&lt;br /&gt;
nrf24l01_initialize_debug(true, width, false); //initialize the 24L01 to the debug configuration as RX, 1  data byte, and auto-ack disabled&lt;br /&gt;
&lt;br /&gt;
while(!(nrf24l01_irq_pin_active() &amp;amp;&amp;amp; nrf24l01_irq_rx_dr_active())); //wait to receive a packet&lt;br /&gt;
&lt;br /&gt;
nrf24l01_read_rx_payload(&amp;amp;data, width); //get the payload into data&lt;br /&gt;
&lt;br /&gt;
nrf24l01_irq_clear_all(); //clear interrupts&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A fully functional [[media:nrf-rx.c|receiver c-file]] is available. It is intended to work with the transmitter code file, available above, and allows for a variable payload.&lt;br /&gt;
&lt;br /&gt;
===Handling Multi-byte Payloads===&lt;br /&gt;
Transmitting and receiving payloads of widths larger than one byte are handled the same exact way as described as above, except that instead of having a a single char data variable, you would have an array of chars as your data variable. Then rather then pass in the memory of address of &amp;lt;code&amp;gt;data &amp;lt;/code&amp;gt; you can simply pass in &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt; itself,  because in C, the variable representing an array is synonymous with the memory address of its first element. Examples of this are available in the attached C files.&lt;br /&gt;
&lt;br /&gt;
===Bidirectional Communication===&lt;br /&gt;
While technically the nrf24l01+ chip can only be in one mode (transmitting/receiving) at a given instant, with some clever programming you can still get a bidirectional link established between two chips. The [[media:nrf-bidirectional.c| full code for bidirectional communication]] is available on this page. Basically, the chip sits in receiver mode, listening for any incoming packets. If it receives one, it displays it to the screen. However, there in the event that a key is pressed on the local terminal, the PIC switches the mode from receiving to transmitting, transmits the data received locally, and then goes back to receiver mode.   It is not a perfect system because if a packet reaches a chip while the chip is in the middle of transmitting a packet itself, it will not pick up the packet in the air. However, the chance of this sort of situation happening would be rare, depending on the application of the system. &lt;br /&gt;
&lt;br /&gt;
To establish a bidirectional link, both PICs should have the same bidirectional c-file loaded (but this is not necessary: e.g. one PIC could only be able to transmit, and it would still be a viable one-way link ). If the on air data rate is set to 1 Mbps, then this bidirectional c-file is compatible with the [http://www.sparkfun.com/commerce/product_info.php?products_id=9019 Nordic USB Serial Converter] (note that the Nordic USB-Serial converter is only compatible with a payload width of four bytes). The payload width of the bidirectional link can be adjusted with the &amp;quot;[&amp;quot; and &amp;quot;]&amp;quot; keys, exactly as with the above code.&lt;br /&gt;
&lt;br /&gt;
==Latency and Data Rates==&lt;br /&gt;
&lt;br /&gt;
Basic timed tests were done to find out how long it took to transmit and receive different sized payloads, as well as the latency involved with transmission.&lt;br /&gt;
&lt;br /&gt;
To measure transmission latency, an oscilloscope was used to time how long it took before transmission was complete. For instance, something like this was used:&lt;br /&gt;
 [[Image:nrf-latency.jpg|thumb|Plot of Transmission Latency]]&lt;br /&gt;
[[Image:bps-nrf24l01.jpg|thumb|Plot of Data Rates]]&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
while(1){&lt;br /&gt;
	if (!swUser){&lt;br /&gt;
			PIN_D1=1; //raise test pin&lt;br /&gt;
&lt;br /&gt;
			nrf24l01_write_tx_payload(dataToSend, width, true); //transmit char array over RF&lt;br /&gt;
			&lt;br /&gt;
			//wait until the packet has been sent&lt;br /&gt;
			while(!(nrf24l01_irq_pin_active() &amp;amp;&amp;amp; nrf24l01_irq_tx_ds_active()));&lt;br /&gt;
&lt;br /&gt;
			PIN_D1=0; //lower test pin&lt;br /&gt;
			nrf24l01_irq_clear_all(); //clear all interrupts in the 24L01&lt;br /&gt;
          }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Three measurements of time to transmit were done for each payload size. It should be noted that these results are completely independent of whether or not the transmission successfully made it to a receiver; in fact, these tests were done without a receiving PIC. The results seem to indicate a latency of 178 microseconds.&lt;br /&gt;
&lt;br /&gt;
Throughput tests were done by sending a packet wirelessly, then timing how long it took to get it back. A pin was raised to high while waiting and then dropped when it was received. These periods were then measured on an oscilloscope, and then averaged. The times used were only those that had 100% return rate. However, the accuracy of these packets was not checked beyond the built in CRC error-checking within the packets themselves. The rates here are to go send out a transmission and then receive it back, so the rate should be doubled for only transmitting in one direction.&lt;/div&gt;</summary>
		<author><name>AndrewKessler</name></author>
	</entry>
	<entry>
		<id>https://hades.mech.northwestern.edu//index.php?title=PIC32MX:_High-speed_Wireless_Communication&amp;diff=19039</id>
		<title>PIC32MX: High-speed Wireless Communication</title>
		<link rel="alternate" type="text/html" href="https://hades.mech.northwestern.edu//index.php?title=PIC32MX:_High-speed_Wireless_Communication&amp;diff=19039"/>
		<updated>2010-09-17T16:07:50Z</updated>

		<summary type="html">&lt;p&gt;AndrewKessler: /* Latency and Data Rates */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Overview ==&lt;br /&gt;
&lt;br /&gt;
[[Image:nrf-pic1.jpg|thumb|nrf24L01+ wireless chip with pins attatched]]&lt;br /&gt;
This wiki describes how to wire a [http://www.sparkfun.com/commerce/product_info.php?products_id=691 nRF24L01+ chip] (&amp;quot;wireless chip&amp;quot;) to a PIC32 board and includes annotated code describing the functions that facilitate the transmitting and receiving of wireless data. A  [[media:Wireless-ppt.pdf|PowerPoint presentation]] covering much of the introductory information available on this page is also available. &lt;br /&gt;
&lt;br /&gt;
To operate the system, you must properly connect the wireless chips to the PIC32s, load the transmitter code onto the PIC that you wish to act as a transmitter, load the receiver code onto the PIC that you wish to act as a receiver, properly connect an RS232 cable to the PIC and open a serial communication program (e.g. HyperTerminal or [http://chiark.greenend.org.uk/~sgtatham/putty/download.html putty]), and turn the NU32 boards on. If you use the c-files provided on this pages (and everything else is set up properly), the transmitting PIC will broadcast  any characters received from the PC via RS232, and the receiving PIC will display what it receives from wireless link on the PC via RS232. The payload width can be adjusted using the &amp;quot;[&amp;quot; and &amp;quot;]&amp;quot; keys on both the transmitting and receiving PICs. Both wireless chips must be set to the same payload width in order to communicate. Payload widths may vary from 1 to 32. The transmitting PIC will not transmit until enough characters have been entered to fill a payload. Once enough characters have been entered into the transmitting PIC, the serial display will move to a new line to signal transmission.&lt;br /&gt;
&lt;br /&gt;
==Chip Basics==&lt;br /&gt;
The nrf24L01+ Module is a breakout of the nrf24L01+ 2.4 GHz transceiver, with an on board antenna. In order to get a wireless link up and running, the following parameters must be consistent between a transmitter and receiver chip:&lt;br /&gt;
&lt;br /&gt;
===Channels===&lt;br /&gt;
The channel of the nrf24L01+ chip is the frequency that it broadcasts and receives data from. The channel can range from 2.4 GHz to 2.525 GHz, at intervals no more than 1 MHz. The exact distance between channels is dependent on the on air data rate. Two wireless chips must be tuned to the same channel in order to communicate.  See the Air Data Rate section for necessary channel spacing.&lt;br /&gt;
&lt;br /&gt;
===Air Data Rate===&lt;br /&gt;
The air data rate is the rate at which the chip transmits bits wirelessly (and the rate at which it looks for them). The nrf24L01+ chip has three selectable data rates: 250 kbps, 1 Mbps, and 2 Mbps. Faster data rates draw less current, but require a greater distance between channels. Slower data rates give you the option of more channels and better receiver sensitivity, for the obvious trade off of speed. Data rates of 250 kbps and 1 Mbps require channel spacing of at least 1 MHz (allowing for 125 unique channels), and a data rate of 2 Mbps requires spacing of 2 MHz between channels (allowing for 62 channels).  Two wireless chips will not be able to communicate if they are not set to the same on air data rate.&lt;br /&gt;
&lt;br /&gt;
===Payload Width===&lt;br /&gt;
The payload is the actual data you are trying to send over a wireless link, and the payload width is how many bytes are contained within each payload. The nfr24L01+ is capable of supporting payloads up to 32 bytes. A transmitter and receiver must be set to the same payload in order to communicate. Transmission speeds for different sizes payloads are analyzed below. &lt;br /&gt;
&lt;br /&gt;
===Addresses &amp;amp; Pipes===&lt;br /&gt;
Every wireless transmission is preceded by the address of the intended receiver. The nrf24L01+ chip has 6 different receiving pipes, which means it may act as 6 receivers with 6 different addresses. Addresses may be three, four, or five bytes long. The addresses for pipe 0 and 1 may be completely different, but the addresses for pipes 2, 3, and 4 may only differ from the address of pipe 1 by their least significant byte. All active pipes feed into the same 3-packet-deep  incoming transmission queue.  Each pipe may also be set to a expect a different payload width.&lt;br /&gt;
&lt;br /&gt;
== Circuit ==&lt;br /&gt;
&lt;br /&gt;
[[Image:Wireless-circuit.jpg|thumb|Schematic of the nRF24L01+ connected to the PIC32_NU32 board]]&lt;br /&gt;
&lt;br /&gt;
The nrf24L01+ chip has 8 pins that need to be wired to the PIC (all I/O are relative to PIC):&lt;br /&gt;
&lt;br /&gt;
*Vcc: +3.3 Vdc supply&amp;lt;br&amp;gt;&lt;br /&gt;
*CE:  uC pin C1 (input)&amp;lt;br&amp;gt;&lt;br /&gt;
*CSN: uC pin C2 (output) &amp;lt;br&amp;gt;&lt;br /&gt;
*SCK: uC pin D10, configured as SCK(SPI) (output)&amp;lt;br&amp;gt;&lt;br /&gt;
*MOSI: uC pin D0, configured as SDO(SPI) (output) &amp;lt;br&amp;gt;&lt;br /&gt;
*MISO: uC pin C4, configured as SDI(SPI) (input)&amp;lt;br&amp;gt;&lt;br /&gt;
*IRQ: uC pin B0 (input) &amp;lt;br&amp;gt;&lt;br /&gt;
*GND: common digital ground&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The +3.3V and ground are provided by the NU32 board. The term &amp;quot;uC&amp;quot; above stands for microcontroller, which is the PIC32 in our case. &lt;br /&gt;
&lt;br /&gt;
Descriptions of the wireless chip&amp;#039;s pins can be found in Brennan Ball&amp;#039;s DIYembedded [http://www.diyembedded.com/tutorials/nrf24l01_0/nrf24l01_tutorial_0.pdf Tutorial 0]. The SCK, MOSI, and MISO pins interface with the SPI on the PIC32 which allows for communication between the PIC and the wireless chip. The GPIO pins will be initialized as digital inputs or outputs in the code to enable/disable the wireless chip and check the wireless data transfer/receive stats.&lt;br /&gt;
&lt;br /&gt;
In order to print information from the PIC to the PC, we need to wire an [[PIC_RS232]] cable&amp;#039;s transfer and receive lines to the UART ports of the NU32 board (F4, F5).&lt;br /&gt;
&lt;br /&gt;
==Code==&lt;br /&gt;
&lt;br /&gt;
===Driver===&lt;br /&gt;
Besides the main C files for the transmitter and receiver, the project also needs the [[media:Wireless-files.zip|nRF24L01.h header file and C file]]. These driver files were created by Brennan Ball, and are explained in detail in his [http://blog.diyembedded.com/ tutorials]. The following things must be changed in the header file available on his website to make it compatible with the NU32 board:&lt;br /&gt;
*pin registers and masks must be set to the appropriate values&lt;br /&gt;
*the &amp;quot;HardwareProfile.h&amp;quot; NU32 specific file must be included &lt;br /&gt;
&lt;br /&gt;
These changes are accounted for the the driver available on this page. All of the SPI functions trace back to a single function to send and read a single byte, which must be defined in the main c file. &lt;br /&gt;
&lt;br /&gt;
This function is available here: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 unsigned char spi_send_read_byte(unsigned char byte) {&lt;br /&gt;
  	 unsigned short	txData, rxData; // transmit, receive characters&lt;br /&gt;
   	 int chn = 1; // SPI channel to use (1 or 2)&lt;br /&gt;
  	 &lt;br /&gt;
   	 txData = byte; // take inputted byte and store into txData   &lt;br /&gt;
   	 SpiChnPutC(chn, txData);			// send data&lt;br /&gt;
 	 rxData = SpiChnGetC(chn);			// retreive over channel chn the received data into rxData&lt;br /&gt;
    &lt;br /&gt;
  	 return rxData; &lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
===Initialization Functions===&lt;br /&gt;
In order to get a wireless link up and running, you will need to initialize both the wireless chip and SPI communication on the PIC. &lt;br /&gt;
To intialize SPI on the PIC, create the following function in your main C file:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;void SpiInitDevice(int chn, int isMaster, int frmEn, int frmMaster) {&lt;br /&gt;
   	 unsigned int config = SPI_CON_MODE8|SPI_CON_SMP|SPI_CON_ON;	// SPI configuration word&lt;br /&gt;
   	 if(isMaster)&lt;br /&gt;
   	 {&lt;br /&gt;
   		 config|=SPI_CON_MSTEN;&lt;br /&gt;
   	 }&lt;br /&gt;
   	 if(frmEn)&lt;br /&gt;
   	 {&lt;br /&gt;
   		 config|=SPI_CON_FRMEN;&lt;br /&gt;
   		 if(!frmMaster) {   &lt;br /&gt;
   			 config|=SPI_CON_FRMSYNC;&lt;br /&gt;
      	 }&lt;br /&gt;
   	 }&lt;br /&gt;
  	 SpiChnOpen(chn, config, 4);	// divide fpb by 4, configure the I/O ports. Not using SS in this example&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
You can then call this function with the call &amp;lt;code&amp;gt; SpiInitDevice(1,1,0,0) &amp;lt;/code&amp;gt; to initalize SPI channel 1 on the PIC. &lt;br /&gt;
&lt;br /&gt;
To initialize the nrf24L01+ chip itself, you have to options. You can either use &amp;lt;code&amp;gt; nrf24L01_initialize(..) &amp;lt;/code&amp;gt; which gives  you the opportunity to manually define every register in the chip right from the start. However, this function has 21 arguments, so it is not the most convenient to use if you don&amp;#039;t have to. Instead, you can use &amp;lt;code&amp;gt; nrf24L01_initialize_debug(bool rx, int width, bool auto_ack_on) &amp;lt;/code&amp;gt;, which gives you the option to specify whether or not the chip is a receiver or transmitter, what the payload width is, and whether or not to enable auto-acknowledge. However, it limits you to Pipe 0, an air data rate of 2 Mpbs, and RF Channel 2. However, these limitations can be adjusted easily after initialization using additional functions (see the library for all available functions). So, for example, to initialize your chip as a transmitter with a payload width of one byte and no auto-acknowledgement, you could call &amp;lt;code&amp;gt; nrf24L01_initialize_debug(0,1,0)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If you wish to display information to the screen or receive information from the keyboard, you will have to initialize the RS232 connection as well. This can be done with the following code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
int pbClk = SYSTEMConfigPerformance(SYS_FREQ);&lt;br /&gt;
initUART2(pbClk);&lt;br /&gt;
&lt;br /&gt;
 void initUART2(int pbClk) {&lt;br /&gt;
  	 #define config1 	UART_EN | UART_IDLE_CON | UART_RX_TX | UART_DIS_WAKE | UART_DIS_LOOPBACK | UART_DIS_ABAUD | UART_NO_PAR_8BIT | UART_1STOPBIT | UART_IRDA_DIS | UART_DIS_BCLK_CTS_RTS| UART_NORMAL_RX | UART_BRGH_SIXTEEN&lt;br /&gt;
  	 #define config2		UART_TX_PIN_LOW | UART_RX_ENABLE | UART_TX_ENABLE | UART_INT_TX | UART_INT_RX_CHAR | UART_ADR_DETECT_DIS | UART_RX_OVERRUN_CLEAR	&lt;br /&gt;
   	 OpenUART2( config1, config2, pbClk/16/DESIRED_BAUDRATE-1);	// calculate actual BAUD generate value.&lt;br /&gt;
   	 ConfigIntUART2(UART_INT_PR2 | UART_RX_INT_EN);&lt;br /&gt;
   	 //INTEnableSystemMultiVectoredInt(); //interrupts enabled?&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Transmitter Code===&lt;br /&gt;
&lt;br /&gt;
Wirelessly transmitting data requires three steps:&lt;br /&gt;
&lt;br /&gt;
*initialize nrf24L01+ as transmitter&lt;br /&gt;
*transmit packet&lt;br /&gt;
*wait for payload to be sent&lt;br /&gt;
&lt;br /&gt;
A basic outline for such a procedure would look like:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
char data = &amp;#039;x&amp;#039;; //data to send&lt;br /&gt;
int width = 1; //width of payload&lt;br /&gt;
&lt;br /&gt;
nrf24l01_initialize_debug(false, width, false); //initialize the 24L01 to the debug configuration as TX, 1  data byte, and auto-ack disabled&lt;br /&gt;
&lt;br /&gt;
nrf24l01_write_tx_payload(&amp;amp;data, width, true); //add char to Tx queue, and transmit immediately  (char * data, int width, bool transmit_now)&lt;br /&gt;
&lt;br /&gt;
while(!(nrf24l01_irq_pin_active() &amp;amp;&amp;amp; nrf24l01_irq_tx_ds_active())); //wait until IRQ status tells us that it is done transmitting&lt;br /&gt;
&lt;br /&gt;
nrf24l01_irq_clear_all(); //clear all interrupts in the 24L01&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A fully functional [[media:nrf-tx.c|transmitter c-file]] is available. It is intended to work with the receiving code file, available below, and allows for a variable payload.&lt;br /&gt;
&lt;br /&gt;
===Receiver Code===&lt;br /&gt;
Similarly, receiving data from a wireless link requires three steps:&lt;br /&gt;
*initialize nrf24L01+ as receiver&lt;br /&gt;
*wait for incoming packet&lt;br /&gt;
*write packet to memory&lt;br /&gt;
&lt;br /&gt;
That would look like: &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
char data; //variable to recieve incoming data&lt;br /&gt;
int width = 1; //width of payload&lt;br /&gt;
&lt;br /&gt;
nrf24l01_initialize_debug(true, width, false); //initialize the 24L01 to the debug configuration as RX, 1  data byte, and auto-ack disabled&lt;br /&gt;
&lt;br /&gt;
while(!(nrf24l01_irq_pin_active() &amp;amp;&amp;amp; nrf24l01_irq_rx_dr_active())); //wait to receive a packet&lt;br /&gt;
&lt;br /&gt;
nrf24l01_read_rx_payload(&amp;amp;data, width); //get the payload into data&lt;br /&gt;
&lt;br /&gt;
nrf24l01_irq_clear_all(); //clear interrupts&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A fully functional [[media:nrf-rx.c|receiver c-file]] is available. It is intended to work with the transmitter code file, available above, and allows for a variable payload.&lt;br /&gt;
&lt;br /&gt;
===Handling Multi-byte Payloads===&lt;br /&gt;
Transmitting and receiving payloads of widths larger than one byte are handled the same exact way as described as above, except that instead of having a a single char data variable, you would have an array of chars as your data variable. Then rather then pass in the memory of address of &amp;lt;code&amp;gt;data &amp;lt;/code&amp;gt; you can simply pass in &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt; itself,  because in C, the variable representing an array is synonymous with the memory address of its first element. Examples of this are available in the attached C files.&lt;br /&gt;
&lt;br /&gt;
===Bidirectional Communication===&lt;br /&gt;
While technically the nrf24l01+ chip can only be in one mode (transmitting/receiving) at a given instant, with some clever programming you can still get a bidirectional link established between two chips. The [[media:nrf-bidirectional.c| full code for bidirectional communication]] is available on this page. Basically, the chip sits in receiver mode, listening for any incoming packets. If it receives one, it displays it to the screen. However, there in the event that a key is pressed on the local terminal, the PIC switches the mode from receiving to transmitting, transmits the data received locally, and then goes back to receiver mode.   It is not a perfect system because if a packet reaches a chip while the chip is in the middle of transmitting a packet itself, it will not pick up the packet in the air. However, the chance of this sort of situation happening would be rare, depending on the application of the system. &lt;br /&gt;
&lt;br /&gt;
To establish a bidirectional link, both PICs should have the same bidirectional c-file loaded (but this is not necessary: e.g. one PIC could only be able to transmit, and it would still be a viable one-way link ). If the on air data rate is set to 1 Mbps, then this bidirectional c-file is compatible with the [http://www.sparkfun.com/commerce/product_info.php?products_id=9019 Nordic USB Serial Converter] (note that the Nordic USB-Serial converter is only compatible with a payload width of four bytes). The payload width of the bidirectional link can be adjusted with the &amp;quot;[&amp;quot; and &amp;quot;]&amp;quot; keys, exactly as with the above code.&lt;br /&gt;
&lt;br /&gt;
==Latency and Data Rates==&lt;br /&gt;
&lt;br /&gt;
Basic timed tests were done to find out how long it took to transmit and receive different sized payloads, as well as the latency involved with transmission.&lt;br /&gt;
&lt;br /&gt;
To measure transmission latency, an oscilloscope was used to time how long it took before transmission was complete. For instance, something like this was used:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
while(1){&lt;br /&gt;
	if (!swUser){&lt;br /&gt;
			PIN_D1=1; //raise test pin&lt;br /&gt;
&lt;br /&gt;
			nrf24l01_write_tx_payload(dataToSend, width, true); //transmit char array over RF&lt;br /&gt;
			&lt;br /&gt;
			//wait until the packet has been sent&lt;br /&gt;
			while(!(nrf24l01_irq_pin_active() &amp;amp;&amp;amp; nrf24l01_irq_tx_ds_active()));&lt;br /&gt;
&lt;br /&gt;
			PIN_D1=0; //lower test pin&lt;br /&gt;
			nrf24l01_irq_clear_all(); //clear all interrupts in the 24L01&lt;br /&gt;
          }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
 [[Image:nrf-latency.jpg|thumb|Plot of Transmission Latency]]&lt;br /&gt;
Three measurements of time to transmit were done for each payload size. It should be noted that these results are completely independent of whether or not the transmission successfully made it to a receiver; in fact, these tests were done without a receiving PIC. The results seem to indicate a latency of 178 microseconds.&lt;br /&gt;
&lt;br /&gt;
Throughput tests were done by sending a packet wirelessly, then timing how long it took to get it back. A pin was raised to high while waiting and then dropped when it was received. These periods were then measured on an oscilloscope, and then averaged. The times used were only those that had 100% return rate. However, the accuracy of these packets was not checked beyond the built in CRC error-checking within the packets themselves. The rates here are to go send out a transmission and then receive it back, so the rate should be doubled for only transmitting in one direction.&lt;br /&gt;
[[Image:bps-nrf24l01.jpg|thumb|Plot of Data Rates]]&lt;/div&gt;</summary>
		<author><name>AndrewKessler</name></author>
	</entry>
	<entry>
		<id>https://hades.mech.northwestern.edu//index.php?title=PIC32MX:_High-speed_Wireless_Communication&amp;diff=19038</id>
		<title>PIC32MX: High-speed Wireless Communication</title>
		<link rel="alternate" type="text/html" href="https://hades.mech.northwestern.edu//index.php?title=PIC32MX:_High-speed_Wireless_Communication&amp;diff=19038"/>
		<updated>2010-09-17T16:06:53Z</updated>

		<summary type="html">&lt;p&gt;AndrewKessler: /* Latency and Data Rates */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Overview ==&lt;br /&gt;
&lt;br /&gt;
[[Image:nrf-pic1.jpg|thumb|nrf24L01+ wireless chip with pins attatched]]&lt;br /&gt;
This wiki describes how to wire a [http://www.sparkfun.com/commerce/product_info.php?products_id=691 nRF24L01+ chip] (&amp;quot;wireless chip&amp;quot;) to a PIC32 board and includes annotated code describing the functions that facilitate the transmitting and receiving of wireless data. A  [[media:Wireless-ppt.pdf|PowerPoint presentation]] covering much of the introductory information available on this page is also available. &lt;br /&gt;
&lt;br /&gt;
To operate the system, you must properly connect the wireless chips to the PIC32s, load the transmitter code onto the PIC that you wish to act as a transmitter, load the receiver code onto the PIC that you wish to act as a receiver, properly connect an RS232 cable to the PIC and open a serial communication program (e.g. HyperTerminal or [http://chiark.greenend.org.uk/~sgtatham/putty/download.html putty]), and turn the NU32 boards on. If you use the c-files provided on this pages (and everything else is set up properly), the transmitting PIC will broadcast  any characters received from the PC via RS232, and the receiving PIC will display what it receives from wireless link on the PC via RS232. The payload width can be adjusted using the &amp;quot;[&amp;quot; and &amp;quot;]&amp;quot; keys on both the transmitting and receiving PICs. Both wireless chips must be set to the same payload width in order to communicate. Payload widths may vary from 1 to 32. The transmitting PIC will not transmit until enough characters have been entered to fill a payload. Once enough characters have been entered into the transmitting PIC, the serial display will move to a new line to signal transmission.&lt;br /&gt;
&lt;br /&gt;
==Chip Basics==&lt;br /&gt;
The nrf24L01+ Module is a breakout of the nrf24L01+ 2.4 GHz transceiver, with an on board antenna. In order to get a wireless link up and running, the following parameters must be consistent between a transmitter and receiver chip:&lt;br /&gt;
&lt;br /&gt;
===Channels===&lt;br /&gt;
The channel of the nrf24L01+ chip is the frequency that it broadcasts and receives data from. The channel can range from 2.4 GHz to 2.525 GHz, at intervals no more than 1 MHz. The exact distance between channels is dependent on the on air data rate. Two wireless chips must be tuned to the same channel in order to communicate.  See the Air Data Rate section for necessary channel spacing.&lt;br /&gt;
&lt;br /&gt;
===Air Data Rate===&lt;br /&gt;
The air data rate is the rate at which the chip transmits bits wirelessly (and the rate at which it looks for them). The nrf24L01+ chip has three selectable data rates: 250 kbps, 1 Mbps, and 2 Mbps. Faster data rates draw less current, but require a greater distance between channels. Slower data rates give you the option of more channels and better receiver sensitivity, for the obvious trade off of speed. Data rates of 250 kbps and 1 Mbps require channel spacing of at least 1 MHz (allowing for 125 unique channels), and a data rate of 2 Mbps requires spacing of 2 MHz between channels (allowing for 62 channels).  Two wireless chips will not be able to communicate if they are not set to the same on air data rate.&lt;br /&gt;
&lt;br /&gt;
===Payload Width===&lt;br /&gt;
The payload is the actual data you are trying to send over a wireless link, and the payload width is how many bytes are contained within each payload. The nfr24L01+ is capable of supporting payloads up to 32 bytes. A transmitter and receiver must be set to the same payload in order to communicate. Transmission speeds for different sizes payloads are analyzed below. &lt;br /&gt;
&lt;br /&gt;
===Addresses &amp;amp; Pipes===&lt;br /&gt;
Every wireless transmission is preceded by the address of the intended receiver. The nrf24L01+ chip has 6 different receiving pipes, which means it may act as 6 receivers with 6 different addresses. Addresses may be three, four, or five bytes long. The addresses for pipe 0 and 1 may be completely different, but the addresses for pipes 2, 3, and 4 may only differ from the address of pipe 1 by their least significant byte. All active pipes feed into the same 3-packet-deep  incoming transmission queue.  Each pipe may also be set to a expect a different payload width.&lt;br /&gt;
&lt;br /&gt;
== Circuit ==&lt;br /&gt;
&lt;br /&gt;
[[Image:Wireless-circuit.jpg|thumb|Schematic of the nRF24L01+ connected to the PIC32_NU32 board]]&lt;br /&gt;
&lt;br /&gt;
The nrf24L01+ chip has 8 pins that need to be wired to the PIC (all I/O are relative to PIC):&lt;br /&gt;
&lt;br /&gt;
*Vcc: +3.3 Vdc supply&amp;lt;br&amp;gt;&lt;br /&gt;
*CE:  uC pin C1 (input)&amp;lt;br&amp;gt;&lt;br /&gt;
*CSN: uC pin C2 (output) &amp;lt;br&amp;gt;&lt;br /&gt;
*SCK: uC pin D10, configured as SCK(SPI) (output)&amp;lt;br&amp;gt;&lt;br /&gt;
*MOSI: uC pin D0, configured as SDO(SPI) (output) &amp;lt;br&amp;gt;&lt;br /&gt;
*MISO: uC pin C4, configured as SDI(SPI) (input)&amp;lt;br&amp;gt;&lt;br /&gt;
*IRQ: uC pin B0 (input) &amp;lt;br&amp;gt;&lt;br /&gt;
*GND: common digital ground&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The +3.3V and ground are provided by the NU32 board. The term &amp;quot;uC&amp;quot; above stands for microcontroller, which is the PIC32 in our case. &lt;br /&gt;
&lt;br /&gt;
Descriptions of the wireless chip&amp;#039;s pins can be found in Brennan Ball&amp;#039;s DIYembedded [http://www.diyembedded.com/tutorials/nrf24l01_0/nrf24l01_tutorial_0.pdf Tutorial 0]. The SCK, MOSI, and MISO pins interface with the SPI on the PIC32 which allows for communication between the PIC and the wireless chip. The GPIO pins will be initialized as digital inputs or outputs in the code to enable/disable the wireless chip and check the wireless data transfer/receive stats.&lt;br /&gt;
&lt;br /&gt;
In order to print information from the PIC to the PC, we need to wire an [[PIC_RS232]] cable&amp;#039;s transfer and receive lines to the UART ports of the NU32 board (F4, F5).&lt;br /&gt;
&lt;br /&gt;
==Code==&lt;br /&gt;
&lt;br /&gt;
===Driver===&lt;br /&gt;
Besides the main C files for the transmitter and receiver, the project also needs the [[media:Wireless-files.zip|nRF24L01.h header file and C file]]. These driver files were created by Brennan Ball, and are explained in detail in his [http://blog.diyembedded.com/ tutorials]. The following things must be changed in the header file available on his website to make it compatible with the NU32 board:&lt;br /&gt;
*pin registers and masks must be set to the appropriate values&lt;br /&gt;
*the &amp;quot;HardwareProfile.h&amp;quot; NU32 specific file must be included &lt;br /&gt;
&lt;br /&gt;
These changes are accounted for the the driver available on this page. All of the SPI functions trace back to a single function to send and read a single byte, which must be defined in the main c file. &lt;br /&gt;
&lt;br /&gt;
This function is available here: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 unsigned char spi_send_read_byte(unsigned char byte) {&lt;br /&gt;
  	 unsigned short	txData, rxData; // transmit, receive characters&lt;br /&gt;
   	 int chn = 1; // SPI channel to use (1 or 2)&lt;br /&gt;
  	 &lt;br /&gt;
   	 txData = byte; // take inputted byte and store into txData   &lt;br /&gt;
   	 SpiChnPutC(chn, txData);			// send data&lt;br /&gt;
 	 rxData = SpiChnGetC(chn);			// retreive over channel chn the received data into rxData&lt;br /&gt;
    &lt;br /&gt;
  	 return rxData; &lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
===Initialization Functions===&lt;br /&gt;
In order to get a wireless link up and running, you will need to initialize both the wireless chip and SPI communication on the PIC. &lt;br /&gt;
To intialize SPI on the PIC, create the following function in your main C file:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;void SpiInitDevice(int chn, int isMaster, int frmEn, int frmMaster) {&lt;br /&gt;
   	 unsigned int config = SPI_CON_MODE8|SPI_CON_SMP|SPI_CON_ON;	// SPI configuration word&lt;br /&gt;
   	 if(isMaster)&lt;br /&gt;
   	 {&lt;br /&gt;
   		 config|=SPI_CON_MSTEN;&lt;br /&gt;
   	 }&lt;br /&gt;
   	 if(frmEn)&lt;br /&gt;
   	 {&lt;br /&gt;
   		 config|=SPI_CON_FRMEN;&lt;br /&gt;
   		 if(!frmMaster) {   &lt;br /&gt;
   			 config|=SPI_CON_FRMSYNC;&lt;br /&gt;
      	 }&lt;br /&gt;
   	 }&lt;br /&gt;
  	 SpiChnOpen(chn, config, 4);	// divide fpb by 4, configure the I/O ports. Not using SS in this example&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
You can then call this function with the call &amp;lt;code&amp;gt; SpiInitDevice(1,1,0,0) &amp;lt;/code&amp;gt; to initalize SPI channel 1 on the PIC. &lt;br /&gt;
&lt;br /&gt;
To initialize the nrf24L01+ chip itself, you have to options. You can either use &amp;lt;code&amp;gt; nrf24L01_initialize(..) &amp;lt;/code&amp;gt; which gives  you the opportunity to manually define every register in the chip right from the start. However, this function has 21 arguments, so it is not the most convenient to use if you don&amp;#039;t have to. Instead, you can use &amp;lt;code&amp;gt; nrf24L01_initialize_debug(bool rx, int width, bool auto_ack_on) &amp;lt;/code&amp;gt;, which gives you the option to specify whether or not the chip is a receiver or transmitter, what the payload width is, and whether or not to enable auto-acknowledge. However, it limits you to Pipe 0, an air data rate of 2 Mpbs, and RF Channel 2. However, these limitations can be adjusted easily after initialization using additional functions (see the library for all available functions). So, for example, to initialize your chip as a transmitter with a payload width of one byte and no auto-acknowledgement, you could call &amp;lt;code&amp;gt; nrf24L01_initialize_debug(0,1,0)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If you wish to display information to the screen or receive information from the keyboard, you will have to initialize the RS232 connection as well. This can be done with the following code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
int pbClk = SYSTEMConfigPerformance(SYS_FREQ);&lt;br /&gt;
initUART2(pbClk);&lt;br /&gt;
&lt;br /&gt;
 void initUART2(int pbClk) {&lt;br /&gt;
  	 #define config1 	UART_EN | UART_IDLE_CON | UART_RX_TX | UART_DIS_WAKE | UART_DIS_LOOPBACK | UART_DIS_ABAUD | UART_NO_PAR_8BIT | UART_1STOPBIT | UART_IRDA_DIS | UART_DIS_BCLK_CTS_RTS| UART_NORMAL_RX | UART_BRGH_SIXTEEN&lt;br /&gt;
  	 #define config2		UART_TX_PIN_LOW | UART_RX_ENABLE | UART_TX_ENABLE | UART_INT_TX | UART_INT_RX_CHAR | UART_ADR_DETECT_DIS | UART_RX_OVERRUN_CLEAR	&lt;br /&gt;
   	 OpenUART2( config1, config2, pbClk/16/DESIRED_BAUDRATE-1);	// calculate actual BAUD generate value.&lt;br /&gt;
   	 ConfigIntUART2(UART_INT_PR2 | UART_RX_INT_EN);&lt;br /&gt;
   	 //INTEnableSystemMultiVectoredInt(); //interrupts enabled?&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Transmitter Code===&lt;br /&gt;
&lt;br /&gt;
Wirelessly transmitting data requires three steps:&lt;br /&gt;
&lt;br /&gt;
*initialize nrf24L01+ as transmitter&lt;br /&gt;
*transmit packet&lt;br /&gt;
*wait for payload to be sent&lt;br /&gt;
&lt;br /&gt;
A basic outline for such a procedure would look like:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
char data = &amp;#039;x&amp;#039;; //data to send&lt;br /&gt;
int width = 1; //width of payload&lt;br /&gt;
&lt;br /&gt;
nrf24l01_initialize_debug(false, width, false); //initialize the 24L01 to the debug configuration as TX, 1  data byte, and auto-ack disabled&lt;br /&gt;
&lt;br /&gt;
nrf24l01_write_tx_payload(&amp;amp;data, width, true); //add char to Tx queue, and transmit immediately  (char * data, int width, bool transmit_now)&lt;br /&gt;
&lt;br /&gt;
while(!(nrf24l01_irq_pin_active() &amp;amp;&amp;amp; nrf24l01_irq_tx_ds_active())); //wait until IRQ status tells us that it is done transmitting&lt;br /&gt;
&lt;br /&gt;
nrf24l01_irq_clear_all(); //clear all interrupts in the 24L01&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A fully functional [[media:nrf-tx.c|transmitter c-file]] is available. It is intended to work with the receiving code file, available below, and allows for a variable payload.&lt;br /&gt;
&lt;br /&gt;
===Receiver Code===&lt;br /&gt;
Similarly, receiving data from a wireless link requires three steps:&lt;br /&gt;
*initialize nrf24L01+ as receiver&lt;br /&gt;
*wait for incoming packet&lt;br /&gt;
*write packet to memory&lt;br /&gt;
&lt;br /&gt;
That would look like: &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
char data; //variable to recieve incoming data&lt;br /&gt;
int width = 1; //width of payload&lt;br /&gt;
&lt;br /&gt;
nrf24l01_initialize_debug(true, width, false); //initialize the 24L01 to the debug configuration as RX, 1  data byte, and auto-ack disabled&lt;br /&gt;
&lt;br /&gt;
while(!(nrf24l01_irq_pin_active() &amp;amp;&amp;amp; nrf24l01_irq_rx_dr_active())); //wait to receive a packet&lt;br /&gt;
&lt;br /&gt;
nrf24l01_read_rx_payload(&amp;amp;data, width); //get the payload into data&lt;br /&gt;
&lt;br /&gt;
nrf24l01_irq_clear_all(); //clear interrupts&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A fully functional [[media:nrf-rx.c|receiver c-file]] is available. It is intended to work with the transmitter code file, available above, and allows for a variable payload.&lt;br /&gt;
&lt;br /&gt;
===Handling Multi-byte Payloads===&lt;br /&gt;
Transmitting and receiving payloads of widths larger than one byte are handled the same exact way as described as above, except that instead of having a a single char data variable, you would have an array of chars as your data variable. Then rather then pass in the memory of address of &amp;lt;code&amp;gt;data &amp;lt;/code&amp;gt; you can simply pass in &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt; itself,  because in C, the variable representing an array is synonymous with the memory address of its first element. Examples of this are available in the attached C files.&lt;br /&gt;
&lt;br /&gt;
===Bidirectional Communication===&lt;br /&gt;
While technically the nrf24l01+ chip can only be in one mode (transmitting/receiving) at a given instant, with some clever programming you can still get a bidirectional link established between two chips. The [[media:nrf-bidirectional.c| full code for bidirectional communication]] is available on this page. Basically, the chip sits in receiver mode, listening for any incoming packets. If it receives one, it displays it to the screen. However, there in the event that a key is pressed on the local terminal, the PIC switches the mode from receiving to transmitting, transmits the data received locally, and then goes back to receiver mode.   It is not a perfect system because if a packet reaches a chip while the chip is in the middle of transmitting a packet itself, it will not pick up the packet in the air. However, the chance of this sort of situation happening would be rare, depending on the application of the system. &lt;br /&gt;
&lt;br /&gt;
To establish a bidirectional link, both PICs should have the same bidirectional c-file loaded (but this is not necessary: e.g. one PIC could only be able to transmit, and it would still be a viable one-way link ). If the on air data rate is set to 1 Mbps, then this bidirectional c-file is compatible with the [http://www.sparkfun.com/commerce/product_info.php?products_id=9019 Nordic USB Serial Converter] (note that the Nordic USB-Serial converter is only compatible with a payload width of four bytes). The payload width of the bidirectional link can be adjusted with the &amp;quot;[&amp;quot; and &amp;quot;]&amp;quot; keys, exactly as with the above code.&lt;br /&gt;
&lt;br /&gt;
==Latency and Data Rates==&lt;br /&gt;
&lt;br /&gt;
Basic timed tests were done to find out how long it took to transmit and receive different sized payloads, as well as the latency involved with transmission.&lt;br /&gt;
&lt;br /&gt;
===Latency===&lt;br /&gt;
To measure transmission latency, an oscilloscope was used to time how long it took before transmission was complete. For instance, something like this was used:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
while(1){&lt;br /&gt;
	if (!swUser){&lt;br /&gt;
			PIN_D1=1; //raise test pin&lt;br /&gt;
&lt;br /&gt;
			nrf24l01_write_tx_payload(dataToSend, width, true); //transmit char array over RF&lt;br /&gt;
			&lt;br /&gt;
			//wait until the packet has been sent&lt;br /&gt;
			while(!(nrf24l01_irq_pin_active() &amp;amp;&amp;amp; nrf24l01_irq_tx_ds_active()));&lt;br /&gt;
&lt;br /&gt;
			PIN_D1=0; //lower test pin&lt;br /&gt;
			nrf24l01_irq_clear_all(); //clear all interrupts in the 24L01&lt;br /&gt;
          }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
 [[Image:nrf-latency.jpg|thumb|Plot of Transmission Latency]]&lt;br /&gt;
Three measurements of time to transmit were done for each payload size. It should be noted that these results are completely independent of whether or not the transmission successfully made it to a receiver; in fact, these tests were done without a receiving PIC. The results seem to indicate a latency of 178 microseconds.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Throughput===&lt;br /&gt;
These tests were done by sending a packet wirelessly, then timing how long it took to get it back. A pin was raised to high while waiting and then dropped when it was received. These periods were then measured on an oscilloscope, and then averaged. The times used were only those that had 100% return rate. However, the accuracy of these packets was not checked beyond the built in CRC error-checking within the packets themselves. The rates here are to go send out a transmission and then receive it back, so the rate should be doubled for only transmitting in one direction.&lt;br /&gt;
[[Image:bps-nrf24l01.jpg|thumb|Plot of Data Rates]]&lt;/div&gt;</summary>
		<author><name>AndrewKessler</name></author>
	</entry>
	<entry>
		<id>https://hades.mech.northwestern.edu//index.php?title=PIC32MX:_High-speed_Wireless_Communication&amp;diff=19037</id>
		<title>PIC32MX: High-speed Wireless Communication</title>
		<link rel="alternate" type="text/html" href="https://hades.mech.northwestern.edu//index.php?title=PIC32MX:_High-speed_Wireless_Communication&amp;diff=19037"/>
		<updated>2010-09-17T16:06:37Z</updated>

		<summary type="html">&lt;p&gt;AndrewKessler: /* =Throughput */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Overview ==&lt;br /&gt;
&lt;br /&gt;
[[Image:nrf-pic1.jpg|thumb|nrf24L01+ wireless chip with pins attatched]]&lt;br /&gt;
This wiki describes how to wire a [http://www.sparkfun.com/commerce/product_info.php?products_id=691 nRF24L01+ chip] (&amp;quot;wireless chip&amp;quot;) to a PIC32 board and includes annotated code describing the functions that facilitate the transmitting and receiving of wireless data. A  [[media:Wireless-ppt.pdf|PowerPoint presentation]] covering much of the introductory information available on this page is also available. &lt;br /&gt;
&lt;br /&gt;
To operate the system, you must properly connect the wireless chips to the PIC32s, load the transmitter code onto the PIC that you wish to act as a transmitter, load the receiver code onto the PIC that you wish to act as a receiver, properly connect an RS232 cable to the PIC and open a serial communication program (e.g. HyperTerminal or [http://chiark.greenend.org.uk/~sgtatham/putty/download.html putty]), and turn the NU32 boards on. If you use the c-files provided on this pages (and everything else is set up properly), the transmitting PIC will broadcast  any characters received from the PC via RS232, and the receiving PIC will display what it receives from wireless link on the PC via RS232. The payload width can be adjusted using the &amp;quot;[&amp;quot; and &amp;quot;]&amp;quot; keys on both the transmitting and receiving PICs. Both wireless chips must be set to the same payload width in order to communicate. Payload widths may vary from 1 to 32. The transmitting PIC will not transmit until enough characters have been entered to fill a payload. Once enough characters have been entered into the transmitting PIC, the serial display will move to a new line to signal transmission.&lt;br /&gt;
&lt;br /&gt;
==Chip Basics==&lt;br /&gt;
The nrf24L01+ Module is a breakout of the nrf24L01+ 2.4 GHz transceiver, with an on board antenna. In order to get a wireless link up and running, the following parameters must be consistent between a transmitter and receiver chip:&lt;br /&gt;
&lt;br /&gt;
===Channels===&lt;br /&gt;
The channel of the nrf24L01+ chip is the frequency that it broadcasts and receives data from. The channel can range from 2.4 GHz to 2.525 GHz, at intervals no more than 1 MHz. The exact distance between channels is dependent on the on air data rate. Two wireless chips must be tuned to the same channel in order to communicate.  See the Air Data Rate section for necessary channel spacing.&lt;br /&gt;
&lt;br /&gt;
===Air Data Rate===&lt;br /&gt;
The air data rate is the rate at which the chip transmits bits wirelessly (and the rate at which it looks for them). The nrf24L01+ chip has three selectable data rates: 250 kbps, 1 Mbps, and 2 Mbps. Faster data rates draw less current, but require a greater distance between channels. Slower data rates give you the option of more channels and better receiver sensitivity, for the obvious trade off of speed. Data rates of 250 kbps and 1 Mbps require channel spacing of at least 1 MHz (allowing for 125 unique channels), and a data rate of 2 Mbps requires spacing of 2 MHz between channels (allowing for 62 channels).  Two wireless chips will not be able to communicate if they are not set to the same on air data rate.&lt;br /&gt;
&lt;br /&gt;
===Payload Width===&lt;br /&gt;
The payload is the actual data you are trying to send over a wireless link, and the payload width is how many bytes are contained within each payload. The nfr24L01+ is capable of supporting payloads up to 32 bytes. A transmitter and receiver must be set to the same payload in order to communicate. Transmission speeds for different sizes payloads are analyzed below. &lt;br /&gt;
&lt;br /&gt;
===Addresses &amp;amp; Pipes===&lt;br /&gt;
Every wireless transmission is preceded by the address of the intended receiver. The nrf24L01+ chip has 6 different receiving pipes, which means it may act as 6 receivers with 6 different addresses. Addresses may be three, four, or five bytes long. The addresses for pipe 0 and 1 may be completely different, but the addresses for pipes 2, 3, and 4 may only differ from the address of pipe 1 by their least significant byte. All active pipes feed into the same 3-packet-deep  incoming transmission queue.  Each pipe may also be set to a expect a different payload width.&lt;br /&gt;
&lt;br /&gt;
== Circuit ==&lt;br /&gt;
&lt;br /&gt;
[[Image:Wireless-circuit.jpg|thumb|Schematic of the nRF24L01+ connected to the PIC32_NU32 board]]&lt;br /&gt;
&lt;br /&gt;
The nrf24L01+ chip has 8 pins that need to be wired to the PIC (all I/O are relative to PIC):&lt;br /&gt;
&lt;br /&gt;
*Vcc: +3.3 Vdc supply&amp;lt;br&amp;gt;&lt;br /&gt;
*CE:  uC pin C1 (input)&amp;lt;br&amp;gt;&lt;br /&gt;
*CSN: uC pin C2 (output) &amp;lt;br&amp;gt;&lt;br /&gt;
*SCK: uC pin D10, configured as SCK(SPI) (output)&amp;lt;br&amp;gt;&lt;br /&gt;
*MOSI: uC pin D0, configured as SDO(SPI) (output) &amp;lt;br&amp;gt;&lt;br /&gt;
*MISO: uC pin C4, configured as SDI(SPI) (input)&amp;lt;br&amp;gt;&lt;br /&gt;
*IRQ: uC pin B0 (input) &amp;lt;br&amp;gt;&lt;br /&gt;
*GND: common digital ground&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The +3.3V and ground are provided by the NU32 board. The term &amp;quot;uC&amp;quot; above stands for microcontroller, which is the PIC32 in our case. &lt;br /&gt;
&lt;br /&gt;
Descriptions of the wireless chip&amp;#039;s pins can be found in Brennan Ball&amp;#039;s DIYembedded [http://www.diyembedded.com/tutorials/nrf24l01_0/nrf24l01_tutorial_0.pdf Tutorial 0]. The SCK, MOSI, and MISO pins interface with the SPI on the PIC32 which allows for communication between the PIC and the wireless chip. The GPIO pins will be initialized as digital inputs or outputs in the code to enable/disable the wireless chip and check the wireless data transfer/receive stats.&lt;br /&gt;
&lt;br /&gt;
In order to print information from the PIC to the PC, we need to wire an [[PIC_RS232]] cable&amp;#039;s transfer and receive lines to the UART ports of the NU32 board (F4, F5).&lt;br /&gt;
&lt;br /&gt;
==Code==&lt;br /&gt;
&lt;br /&gt;
===Driver===&lt;br /&gt;
Besides the main C files for the transmitter and receiver, the project also needs the [[media:Wireless-files.zip|nRF24L01.h header file and C file]]. These driver files were created by Brennan Ball, and are explained in detail in his [http://blog.diyembedded.com/ tutorials]. The following things must be changed in the header file available on his website to make it compatible with the NU32 board:&lt;br /&gt;
*pin registers and masks must be set to the appropriate values&lt;br /&gt;
*the &amp;quot;HardwareProfile.h&amp;quot; NU32 specific file must be included &lt;br /&gt;
&lt;br /&gt;
These changes are accounted for the the driver available on this page. All of the SPI functions trace back to a single function to send and read a single byte, which must be defined in the main c file. &lt;br /&gt;
&lt;br /&gt;
This function is available here: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 unsigned char spi_send_read_byte(unsigned char byte) {&lt;br /&gt;
  	 unsigned short	txData, rxData; // transmit, receive characters&lt;br /&gt;
   	 int chn = 1; // SPI channel to use (1 or 2)&lt;br /&gt;
  	 &lt;br /&gt;
   	 txData = byte; // take inputted byte and store into txData   &lt;br /&gt;
   	 SpiChnPutC(chn, txData);			// send data&lt;br /&gt;
 	 rxData = SpiChnGetC(chn);			// retreive over channel chn the received data into rxData&lt;br /&gt;
    &lt;br /&gt;
  	 return rxData; &lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
===Initialization Functions===&lt;br /&gt;
In order to get a wireless link up and running, you will need to initialize both the wireless chip and SPI communication on the PIC. &lt;br /&gt;
To intialize SPI on the PIC, create the following function in your main C file:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;void SpiInitDevice(int chn, int isMaster, int frmEn, int frmMaster) {&lt;br /&gt;
   	 unsigned int config = SPI_CON_MODE8|SPI_CON_SMP|SPI_CON_ON;	// SPI configuration word&lt;br /&gt;
   	 if(isMaster)&lt;br /&gt;
   	 {&lt;br /&gt;
   		 config|=SPI_CON_MSTEN;&lt;br /&gt;
   	 }&lt;br /&gt;
   	 if(frmEn)&lt;br /&gt;
   	 {&lt;br /&gt;
   		 config|=SPI_CON_FRMEN;&lt;br /&gt;
   		 if(!frmMaster) {   &lt;br /&gt;
   			 config|=SPI_CON_FRMSYNC;&lt;br /&gt;
      	 }&lt;br /&gt;
   	 }&lt;br /&gt;
  	 SpiChnOpen(chn, config, 4);	// divide fpb by 4, configure the I/O ports. Not using SS in this example&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
You can then call this function with the call &amp;lt;code&amp;gt; SpiInitDevice(1,1,0,0) &amp;lt;/code&amp;gt; to initalize SPI channel 1 on the PIC. &lt;br /&gt;
&lt;br /&gt;
To initialize the nrf24L01+ chip itself, you have to options. You can either use &amp;lt;code&amp;gt; nrf24L01_initialize(..) &amp;lt;/code&amp;gt; which gives  you the opportunity to manually define every register in the chip right from the start. However, this function has 21 arguments, so it is not the most convenient to use if you don&amp;#039;t have to. Instead, you can use &amp;lt;code&amp;gt; nrf24L01_initialize_debug(bool rx, int width, bool auto_ack_on) &amp;lt;/code&amp;gt;, which gives you the option to specify whether or not the chip is a receiver or transmitter, what the payload width is, and whether or not to enable auto-acknowledge. However, it limits you to Pipe 0, an air data rate of 2 Mpbs, and RF Channel 2. However, these limitations can be adjusted easily after initialization using additional functions (see the library for all available functions). So, for example, to initialize your chip as a transmitter with a payload width of one byte and no auto-acknowledgement, you could call &amp;lt;code&amp;gt; nrf24L01_initialize_debug(0,1,0)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If you wish to display information to the screen or receive information from the keyboard, you will have to initialize the RS232 connection as well. This can be done with the following code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
int pbClk = SYSTEMConfigPerformance(SYS_FREQ);&lt;br /&gt;
initUART2(pbClk);&lt;br /&gt;
&lt;br /&gt;
 void initUART2(int pbClk) {&lt;br /&gt;
  	 #define config1 	UART_EN | UART_IDLE_CON | UART_RX_TX | UART_DIS_WAKE | UART_DIS_LOOPBACK | UART_DIS_ABAUD | UART_NO_PAR_8BIT | UART_1STOPBIT | UART_IRDA_DIS | UART_DIS_BCLK_CTS_RTS| UART_NORMAL_RX | UART_BRGH_SIXTEEN&lt;br /&gt;
  	 #define config2		UART_TX_PIN_LOW | UART_RX_ENABLE | UART_TX_ENABLE | UART_INT_TX | UART_INT_RX_CHAR | UART_ADR_DETECT_DIS | UART_RX_OVERRUN_CLEAR	&lt;br /&gt;
   	 OpenUART2( config1, config2, pbClk/16/DESIRED_BAUDRATE-1);	// calculate actual BAUD generate value.&lt;br /&gt;
   	 ConfigIntUART2(UART_INT_PR2 | UART_RX_INT_EN);&lt;br /&gt;
   	 //INTEnableSystemMultiVectoredInt(); //interrupts enabled?&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Transmitter Code===&lt;br /&gt;
&lt;br /&gt;
Wirelessly transmitting data requires three steps:&lt;br /&gt;
&lt;br /&gt;
*initialize nrf24L01+ as transmitter&lt;br /&gt;
*transmit packet&lt;br /&gt;
*wait for payload to be sent&lt;br /&gt;
&lt;br /&gt;
A basic outline for such a procedure would look like:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
char data = &amp;#039;x&amp;#039;; //data to send&lt;br /&gt;
int width = 1; //width of payload&lt;br /&gt;
&lt;br /&gt;
nrf24l01_initialize_debug(false, width, false); //initialize the 24L01 to the debug configuration as TX, 1  data byte, and auto-ack disabled&lt;br /&gt;
&lt;br /&gt;
nrf24l01_write_tx_payload(&amp;amp;data, width, true); //add char to Tx queue, and transmit immediately  (char * data, int width, bool transmit_now)&lt;br /&gt;
&lt;br /&gt;
while(!(nrf24l01_irq_pin_active() &amp;amp;&amp;amp; nrf24l01_irq_tx_ds_active())); //wait until IRQ status tells us that it is done transmitting&lt;br /&gt;
&lt;br /&gt;
nrf24l01_irq_clear_all(); //clear all interrupts in the 24L01&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A fully functional [[media:nrf-tx.c|transmitter c-file]] is available. It is intended to work with the receiving code file, available below, and allows for a variable payload.&lt;br /&gt;
&lt;br /&gt;
===Receiver Code===&lt;br /&gt;
Similarly, receiving data from a wireless link requires three steps:&lt;br /&gt;
*initialize nrf24L01+ as receiver&lt;br /&gt;
*wait for incoming packet&lt;br /&gt;
*write packet to memory&lt;br /&gt;
&lt;br /&gt;
That would look like: &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
char data; //variable to recieve incoming data&lt;br /&gt;
int width = 1; //width of payload&lt;br /&gt;
&lt;br /&gt;
nrf24l01_initialize_debug(true, width, false); //initialize the 24L01 to the debug configuration as RX, 1  data byte, and auto-ack disabled&lt;br /&gt;
&lt;br /&gt;
while(!(nrf24l01_irq_pin_active() &amp;amp;&amp;amp; nrf24l01_irq_rx_dr_active())); //wait to receive a packet&lt;br /&gt;
&lt;br /&gt;
nrf24l01_read_rx_payload(&amp;amp;data, width); //get the payload into data&lt;br /&gt;
&lt;br /&gt;
nrf24l01_irq_clear_all(); //clear interrupts&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A fully functional [[media:nrf-rx.c|receiver c-file]] is available. It is intended to work with the transmitter code file, available above, and allows for a variable payload.&lt;br /&gt;
&lt;br /&gt;
===Handling Multi-byte Payloads===&lt;br /&gt;
Transmitting and receiving payloads of widths larger than one byte are handled the same exact way as described as above, except that instead of having a a single char data variable, you would have an array of chars as your data variable. Then rather then pass in the memory of address of &amp;lt;code&amp;gt;data &amp;lt;/code&amp;gt; you can simply pass in &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt; itself,  because in C, the variable representing an array is synonymous with the memory address of its first element. Examples of this are available in the attached C files.&lt;br /&gt;
&lt;br /&gt;
===Bidirectional Communication===&lt;br /&gt;
While technically the nrf24l01+ chip can only be in one mode (transmitting/receiving) at a given instant, with some clever programming you can still get a bidirectional link established between two chips. The [[media:nrf-bidirectional.c| full code for bidirectional communication]] is available on this page. Basically, the chip sits in receiver mode, listening for any incoming packets. If it receives one, it displays it to the screen. However, there in the event that a key is pressed on the local terminal, the PIC switches the mode from receiving to transmitting, transmits the data received locally, and then goes back to receiver mode.   It is not a perfect system because if a packet reaches a chip while the chip is in the middle of transmitting a packet itself, it will not pick up the packet in the air. However, the chance of this sort of situation happening would be rare, depending on the application of the system. &lt;br /&gt;
&lt;br /&gt;
To establish a bidirectional link, both PICs should have the same bidirectional c-file loaded (but this is not necessary: e.g. one PIC could only be able to transmit, and it would still be a viable one-way link ). If the on air data rate is set to 1 Mbps, then this bidirectional c-file is compatible with the [http://www.sparkfun.com/commerce/product_info.php?products_id=9019 Nordic USB Serial Converter] (note that the Nordic USB-Serial converter is only compatible with a payload width of four bytes). The payload width of the bidirectional link can be adjusted with the &amp;quot;[&amp;quot; and &amp;quot;]&amp;quot; keys, exactly as with the above code.&lt;br /&gt;
&lt;br /&gt;
==Latency and Data Rates==&lt;br /&gt;
&lt;br /&gt;
Basic timed tests were done to find out how long it took to transmit and receive different sized payloads, as well as the latency involved with transmission.&lt;br /&gt;
&lt;br /&gt;
===Latency===&lt;br /&gt;
To measure transmission latency, an oscilloscope was used to time how long it took before transmission was complete. For instance, something like this was used:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
while(1){&lt;br /&gt;
	if (!swUser){&lt;br /&gt;
			PIN_D1=1; //raise test pin&lt;br /&gt;
&lt;br /&gt;
			nrf24l01_write_tx_payload(dataToSend, width, true); //transmit char array over RF&lt;br /&gt;
			&lt;br /&gt;
			//wait until the packet has been sent&lt;br /&gt;
			while(!(nrf24l01_irq_pin_active() &amp;amp;&amp;amp; nrf24l01_irq_tx_ds_active()));&lt;br /&gt;
&lt;br /&gt;
			PIN_D1=0; //lower test pin&lt;br /&gt;
			nrf24l01_irq_clear_all(); //clear all interrupts in the 24L01&lt;br /&gt;
          }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Three measurements of time to transmit were done for each payload size. It should be noted that these results are completely independent of whether or not the transmission successfully made it to a receiver; in fact, these tests were done without a receiving PIC. The results seem to indicate a latency of 178 microseconds.&lt;br /&gt;
 [[Image:nrf-latency.jpg|thumb|Plot of Transmission Latency]]&lt;br /&gt;
&lt;br /&gt;
===Throughput===&lt;br /&gt;
These tests were done by sending a packet wirelessly, then timing how long it took to get it back. A pin was raised to high while waiting and then dropped when it was received. These periods were then measured on an oscilloscope, and then averaged. The times used were only those that had 100% return rate. However, the accuracy of these packets was not checked beyond the built in CRC error-checking within the packets themselves. The rates here are to go send out a transmission and then receive it back, so the rate should be doubled for only transmitting in one direction.&lt;br /&gt;
[[Image:bps-nrf24l01.jpg|thumb|Plot of Data Rates]]&lt;/div&gt;</summary>
		<author><name>AndrewKessler</name></author>
	</entry>
	<entry>
		<id>https://hades.mech.northwestern.edu//index.php?title=PIC32MX:_High-speed_Wireless_Communication&amp;diff=19036</id>
		<title>PIC32MX: High-speed Wireless Communication</title>
		<link rel="alternate" type="text/html" href="https://hades.mech.northwestern.edu//index.php?title=PIC32MX:_High-speed_Wireless_Communication&amp;diff=19036"/>
		<updated>2010-09-17T16:06:12Z</updated>

		<summary type="html">&lt;p&gt;AndrewKessler: /* Latency and Data Rates */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Overview ==&lt;br /&gt;
&lt;br /&gt;
[[Image:nrf-pic1.jpg|thumb|nrf24L01+ wireless chip with pins attatched]]&lt;br /&gt;
This wiki describes how to wire a [http://www.sparkfun.com/commerce/product_info.php?products_id=691 nRF24L01+ chip] (&amp;quot;wireless chip&amp;quot;) to a PIC32 board and includes annotated code describing the functions that facilitate the transmitting and receiving of wireless data. A  [[media:Wireless-ppt.pdf|PowerPoint presentation]] covering much of the introductory information available on this page is also available. &lt;br /&gt;
&lt;br /&gt;
To operate the system, you must properly connect the wireless chips to the PIC32s, load the transmitter code onto the PIC that you wish to act as a transmitter, load the receiver code onto the PIC that you wish to act as a receiver, properly connect an RS232 cable to the PIC and open a serial communication program (e.g. HyperTerminal or [http://chiark.greenend.org.uk/~sgtatham/putty/download.html putty]), and turn the NU32 boards on. If you use the c-files provided on this pages (and everything else is set up properly), the transmitting PIC will broadcast  any characters received from the PC via RS232, and the receiving PIC will display what it receives from wireless link on the PC via RS232. The payload width can be adjusted using the &amp;quot;[&amp;quot; and &amp;quot;]&amp;quot; keys on both the transmitting and receiving PICs. Both wireless chips must be set to the same payload width in order to communicate. Payload widths may vary from 1 to 32. The transmitting PIC will not transmit until enough characters have been entered to fill a payload. Once enough characters have been entered into the transmitting PIC, the serial display will move to a new line to signal transmission.&lt;br /&gt;
&lt;br /&gt;
==Chip Basics==&lt;br /&gt;
The nrf24L01+ Module is a breakout of the nrf24L01+ 2.4 GHz transceiver, with an on board antenna. In order to get a wireless link up and running, the following parameters must be consistent between a transmitter and receiver chip:&lt;br /&gt;
&lt;br /&gt;
===Channels===&lt;br /&gt;
The channel of the nrf24L01+ chip is the frequency that it broadcasts and receives data from. The channel can range from 2.4 GHz to 2.525 GHz, at intervals no more than 1 MHz. The exact distance between channels is dependent on the on air data rate. Two wireless chips must be tuned to the same channel in order to communicate.  See the Air Data Rate section for necessary channel spacing.&lt;br /&gt;
&lt;br /&gt;
===Air Data Rate===&lt;br /&gt;
The air data rate is the rate at which the chip transmits bits wirelessly (and the rate at which it looks for them). The nrf24L01+ chip has three selectable data rates: 250 kbps, 1 Mbps, and 2 Mbps. Faster data rates draw less current, but require a greater distance between channels. Slower data rates give you the option of more channels and better receiver sensitivity, for the obvious trade off of speed. Data rates of 250 kbps and 1 Mbps require channel spacing of at least 1 MHz (allowing for 125 unique channels), and a data rate of 2 Mbps requires spacing of 2 MHz between channels (allowing for 62 channels).  Two wireless chips will not be able to communicate if they are not set to the same on air data rate.&lt;br /&gt;
&lt;br /&gt;
===Payload Width===&lt;br /&gt;
The payload is the actual data you are trying to send over a wireless link, and the payload width is how many bytes are contained within each payload. The nfr24L01+ is capable of supporting payloads up to 32 bytes. A transmitter and receiver must be set to the same payload in order to communicate. Transmission speeds for different sizes payloads are analyzed below. &lt;br /&gt;
&lt;br /&gt;
===Addresses &amp;amp; Pipes===&lt;br /&gt;
Every wireless transmission is preceded by the address of the intended receiver. The nrf24L01+ chip has 6 different receiving pipes, which means it may act as 6 receivers with 6 different addresses. Addresses may be three, four, or five bytes long. The addresses for pipe 0 and 1 may be completely different, but the addresses for pipes 2, 3, and 4 may only differ from the address of pipe 1 by their least significant byte. All active pipes feed into the same 3-packet-deep  incoming transmission queue.  Each pipe may also be set to a expect a different payload width.&lt;br /&gt;
&lt;br /&gt;
== Circuit ==&lt;br /&gt;
&lt;br /&gt;
[[Image:Wireless-circuit.jpg|thumb|Schematic of the nRF24L01+ connected to the PIC32_NU32 board]]&lt;br /&gt;
&lt;br /&gt;
The nrf24L01+ chip has 8 pins that need to be wired to the PIC (all I/O are relative to PIC):&lt;br /&gt;
&lt;br /&gt;
*Vcc: +3.3 Vdc supply&amp;lt;br&amp;gt;&lt;br /&gt;
*CE:  uC pin C1 (input)&amp;lt;br&amp;gt;&lt;br /&gt;
*CSN: uC pin C2 (output) &amp;lt;br&amp;gt;&lt;br /&gt;
*SCK: uC pin D10, configured as SCK(SPI) (output)&amp;lt;br&amp;gt;&lt;br /&gt;
*MOSI: uC pin D0, configured as SDO(SPI) (output) &amp;lt;br&amp;gt;&lt;br /&gt;
*MISO: uC pin C4, configured as SDI(SPI) (input)&amp;lt;br&amp;gt;&lt;br /&gt;
*IRQ: uC pin B0 (input) &amp;lt;br&amp;gt;&lt;br /&gt;
*GND: common digital ground&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The +3.3V and ground are provided by the NU32 board. The term &amp;quot;uC&amp;quot; above stands for microcontroller, which is the PIC32 in our case. &lt;br /&gt;
&lt;br /&gt;
Descriptions of the wireless chip&amp;#039;s pins can be found in Brennan Ball&amp;#039;s DIYembedded [http://www.diyembedded.com/tutorials/nrf24l01_0/nrf24l01_tutorial_0.pdf Tutorial 0]. The SCK, MOSI, and MISO pins interface with the SPI on the PIC32 which allows for communication between the PIC and the wireless chip. The GPIO pins will be initialized as digital inputs or outputs in the code to enable/disable the wireless chip and check the wireless data transfer/receive stats.&lt;br /&gt;
&lt;br /&gt;
In order to print information from the PIC to the PC, we need to wire an [[PIC_RS232]] cable&amp;#039;s transfer and receive lines to the UART ports of the NU32 board (F4, F5).&lt;br /&gt;
&lt;br /&gt;
==Code==&lt;br /&gt;
&lt;br /&gt;
===Driver===&lt;br /&gt;
Besides the main C files for the transmitter and receiver, the project also needs the [[media:Wireless-files.zip|nRF24L01.h header file and C file]]. These driver files were created by Brennan Ball, and are explained in detail in his [http://blog.diyembedded.com/ tutorials]. The following things must be changed in the header file available on his website to make it compatible with the NU32 board:&lt;br /&gt;
*pin registers and masks must be set to the appropriate values&lt;br /&gt;
*the &amp;quot;HardwareProfile.h&amp;quot; NU32 specific file must be included &lt;br /&gt;
&lt;br /&gt;
These changes are accounted for the the driver available on this page. All of the SPI functions trace back to a single function to send and read a single byte, which must be defined in the main c file. &lt;br /&gt;
&lt;br /&gt;
This function is available here: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 unsigned char spi_send_read_byte(unsigned char byte) {&lt;br /&gt;
  	 unsigned short	txData, rxData; // transmit, receive characters&lt;br /&gt;
   	 int chn = 1; // SPI channel to use (1 or 2)&lt;br /&gt;
  	 &lt;br /&gt;
   	 txData = byte; // take inputted byte and store into txData   &lt;br /&gt;
   	 SpiChnPutC(chn, txData);			// send data&lt;br /&gt;
 	 rxData = SpiChnGetC(chn);			// retreive over channel chn the received data into rxData&lt;br /&gt;
    &lt;br /&gt;
  	 return rxData; &lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
===Initialization Functions===&lt;br /&gt;
In order to get a wireless link up and running, you will need to initialize both the wireless chip and SPI communication on the PIC. &lt;br /&gt;
To intialize SPI on the PIC, create the following function in your main C file:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;void SpiInitDevice(int chn, int isMaster, int frmEn, int frmMaster) {&lt;br /&gt;
   	 unsigned int config = SPI_CON_MODE8|SPI_CON_SMP|SPI_CON_ON;	// SPI configuration word&lt;br /&gt;
   	 if(isMaster)&lt;br /&gt;
   	 {&lt;br /&gt;
   		 config|=SPI_CON_MSTEN;&lt;br /&gt;
   	 }&lt;br /&gt;
   	 if(frmEn)&lt;br /&gt;
   	 {&lt;br /&gt;
   		 config|=SPI_CON_FRMEN;&lt;br /&gt;
   		 if(!frmMaster) {   &lt;br /&gt;
   			 config|=SPI_CON_FRMSYNC;&lt;br /&gt;
      	 }&lt;br /&gt;
   	 }&lt;br /&gt;
  	 SpiChnOpen(chn, config, 4);	// divide fpb by 4, configure the I/O ports. Not using SS in this example&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
You can then call this function with the call &amp;lt;code&amp;gt; SpiInitDevice(1,1,0,0) &amp;lt;/code&amp;gt; to initalize SPI channel 1 on the PIC. &lt;br /&gt;
&lt;br /&gt;
To initialize the nrf24L01+ chip itself, you have to options. You can either use &amp;lt;code&amp;gt; nrf24L01_initialize(..) &amp;lt;/code&amp;gt; which gives  you the opportunity to manually define every register in the chip right from the start. However, this function has 21 arguments, so it is not the most convenient to use if you don&amp;#039;t have to. Instead, you can use &amp;lt;code&amp;gt; nrf24L01_initialize_debug(bool rx, int width, bool auto_ack_on) &amp;lt;/code&amp;gt;, which gives you the option to specify whether or not the chip is a receiver or transmitter, what the payload width is, and whether or not to enable auto-acknowledge. However, it limits you to Pipe 0, an air data rate of 2 Mpbs, and RF Channel 2. However, these limitations can be adjusted easily after initialization using additional functions (see the library for all available functions). So, for example, to initialize your chip as a transmitter with a payload width of one byte and no auto-acknowledgement, you could call &amp;lt;code&amp;gt; nrf24L01_initialize_debug(0,1,0)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If you wish to display information to the screen or receive information from the keyboard, you will have to initialize the RS232 connection as well. This can be done with the following code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
int pbClk = SYSTEMConfigPerformance(SYS_FREQ);&lt;br /&gt;
initUART2(pbClk);&lt;br /&gt;
&lt;br /&gt;
 void initUART2(int pbClk) {&lt;br /&gt;
  	 #define config1 	UART_EN | UART_IDLE_CON | UART_RX_TX | UART_DIS_WAKE | UART_DIS_LOOPBACK | UART_DIS_ABAUD | UART_NO_PAR_8BIT | UART_1STOPBIT | UART_IRDA_DIS | UART_DIS_BCLK_CTS_RTS| UART_NORMAL_RX | UART_BRGH_SIXTEEN&lt;br /&gt;
  	 #define config2		UART_TX_PIN_LOW | UART_RX_ENABLE | UART_TX_ENABLE | UART_INT_TX | UART_INT_RX_CHAR | UART_ADR_DETECT_DIS | UART_RX_OVERRUN_CLEAR	&lt;br /&gt;
   	 OpenUART2( config1, config2, pbClk/16/DESIRED_BAUDRATE-1);	// calculate actual BAUD generate value.&lt;br /&gt;
   	 ConfigIntUART2(UART_INT_PR2 | UART_RX_INT_EN);&lt;br /&gt;
   	 //INTEnableSystemMultiVectoredInt(); //interrupts enabled?&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Transmitter Code===&lt;br /&gt;
&lt;br /&gt;
Wirelessly transmitting data requires three steps:&lt;br /&gt;
&lt;br /&gt;
*initialize nrf24L01+ as transmitter&lt;br /&gt;
*transmit packet&lt;br /&gt;
*wait for payload to be sent&lt;br /&gt;
&lt;br /&gt;
A basic outline for such a procedure would look like:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
char data = &amp;#039;x&amp;#039;; //data to send&lt;br /&gt;
int width = 1; //width of payload&lt;br /&gt;
&lt;br /&gt;
nrf24l01_initialize_debug(false, width, false); //initialize the 24L01 to the debug configuration as TX, 1  data byte, and auto-ack disabled&lt;br /&gt;
&lt;br /&gt;
nrf24l01_write_tx_payload(&amp;amp;data, width, true); //add char to Tx queue, and transmit immediately  (char * data, int width, bool transmit_now)&lt;br /&gt;
&lt;br /&gt;
while(!(nrf24l01_irq_pin_active() &amp;amp;&amp;amp; nrf24l01_irq_tx_ds_active())); //wait until IRQ status tells us that it is done transmitting&lt;br /&gt;
&lt;br /&gt;
nrf24l01_irq_clear_all(); //clear all interrupts in the 24L01&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A fully functional [[media:nrf-tx.c|transmitter c-file]] is available. It is intended to work with the receiving code file, available below, and allows for a variable payload.&lt;br /&gt;
&lt;br /&gt;
===Receiver Code===&lt;br /&gt;
Similarly, receiving data from a wireless link requires three steps:&lt;br /&gt;
*initialize nrf24L01+ as receiver&lt;br /&gt;
*wait for incoming packet&lt;br /&gt;
*write packet to memory&lt;br /&gt;
&lt;br /&gt;
That would look like: &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
char data; //variable to recieve incoming data&lt;br /&gt;
int width = 1; //width of payload&lt;br /&gt;
&lt;br /&gt;
nrf24l01_initialize_debug(true, width, false); //initialize the 24L01 to the debug configuration as RX, 1  data byte, and auto-ack disabled&lt;br /&gt;
&lt;br /&gt;
while(!(nrf24l01_irq_pin_active() &amp;amp;&amp;amp; nrf24l01_irq_rx_dr_active())); //wait to receive a packet&lt;br /&gt;
&lt;br /&gt;
nrf24l01_read_rx_payload(&amp;amp;data, width); //get the payload into data&lt;br /&gt;
&lt;br /&gt;
nrf24l01_irq_clear_all(); //clear interrupts&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A fully functional [[media:nrf-rx.c|receiver c-file]] is available. It is intended to work with the transmitter code file, available above, and allows for a variable payload.&lt;br /&gt;
&lt;br /&gt;
===Handling Multi-byte Payloads===&lt;br /&gt;
Transmitting and receiving payloads of widths larger than one byte are handled the same exact way as described as above, except that instead of having a a single char data variable, you would have an array of chars as your data variable. Then rather then pass in the memory of address of &amp;lt;code&amp;gt;data &amp;lt;/code&amp;gt; you can simply pass in &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt; itself,  because in C, the variable representing an array is synonymous with the memory address of its first element. Examples of this are available in the attached C files.&lt;br /&gt;
&lt;br /&gt;
===Bidirectional Communication===&lt;br /&gt;
While technically the nrf24l01+ chip can only be in one mode (transmitting/receiving) at a given instant, with some clever programming you can still get a bidirectional link established between two chips. The [[media:nrf-bidirectional.c| full code for bidirectional communication]] is available on this page. Basically, the chip sits in receiver mode, listening for any incoming packets. If it receives one, it displays it to the screen. However, there in the event that a key is pressed on the local terminal, the PIC switches the mode from receiving to transmitting, transmits the data received locally, and then goes back to receiver mode.   It is not a perfect system because if a packet reaches a chip while the chip is in the middle of transmitting a packet itself, it will not pick up the packet in the air. However, the chance of this sort of situation happening would be rare, depending on the application of the system. &lt;br /&gt;
&lt;br /&gt;
To establish a bidirectional link, both PICs should have the same bidirectional c-file loaded (but this is not necessary: e.g. one PIC could only be able to transmit, and it would still be a viable one-way link ). If the on air data rate is set to 1 Mbps, then this bidirectional c-file is compatible with the [http://www.sparkfun.com/commerce/product_info.php?products_id=9019 Nordic USB Serial Converter] (note that the Nordic USB-Serial converter is only compatible with a payload width of four bytes). The payload width of the bidirectional link can be adjusted with the &amp;quot;[&amp;quot; and &amp;quot;]&amp;quot; keys, exactly as with the above code.&lt;br /&gt;
&lt;br /&gt;
==Latency and Data Rates==&lt;br /&gt;
&lt;br /&gt;
Basic timed tests were done to find out how long it took to transmit and receive different sized payloads, as well as the latency involved with transmission.&lt;br /&gt;
&lt;br /&gt;
===Latency===&lt;br /&gt;
To measure transmission latency, an oscilloscope was used to time how long it took before transmission was complete. For instance, something like this was used:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
while(1){&lt;br /&gt;
	if (!swUser){&lt;br /&gt;
			PIN_D1=1; //raise test pin&lt;br /&gt;
&lt;br /&gt;
			nrf24l01_write_tx_payload(dataToSend, width, true); //transmit char array over RF&lt;br /&gt;
			&lt;br /&gt;
			//wait until the packet has been sent&lt;br /&gt;
			while(!(nrf24l01_irq_pin_active() &amp;amp;&amp;amp; nrf24l01_irq_tx_ds_active()));&lt;br /&gt;
&lt;br /&gt;
			PIN_D1=0; //lower test pin&lt;br /&gt;
			nrf24l01_irq_clear_all(); //clear all interrupts in the 24L01&lt;br /&gt;
          }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Three measurements of time to transmit were done for each payload size. It should be noted that these results are completely independent of whether or not the transmission successfully made it to a receiver; in fact, these tests were done without a receiving PIC. The results seem to indicate a latency of 178 microseconds.&lt;br /&gt;
 [[Image:nrf-latency.jpg|thumb|Plot of Transmission Latency]]&lt;br /&gt;
&lt;br /&gt;
===Throughput==&lt;br /&gt;
These tests were done by sending a packet wirelessly, then timing how long it took to get it back. A pin was raised to high while waiting and then dropped when it was received. These periods were then measured on an oscilloscope, and then averaged. The times used were only those that had 100% return rate. However, the accuracy of these packets was not checked beyond the built in CRC error-checking within the packets themselves. The rates here are to go send out a transmission and then receive it back, so the rate should be doubled for only transmitting in one direction.&lt;br /&gt;
[[Image:bps-nrf24l01.jpg|thumb|Plot of Data Rates]]&lt;/div&gt;</summary>
		<author><name>AndrewKessler</name></author>
	</entry>
	<entry>
		<id>https://hades.mech.northwestern.edu//index.php?title=PIC32MX:_High-speed_Wireless_Communication&amp;diff=19035</id>
		<title>PIC32MX: High-speed Wireless Communication</title>
		<link rel="alternate" type="text/html" href="https://hades.mech.northwestern.edu//index.php?title=PIC32MX:_High-speed_Wireless_Communication&amp;diff=19035"/>
		<updated>2010-09-17T16:05:31Z</updated>

		<summary type="html">&lt;p&gt;AndrewKessler: /* Latency and Data Rates */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Overview ==&lt;br /&gt;
&lt;br /&gt;
[[Image:nrf-pic1.jpg|thumb|nrf24L01+ wireless chip with pins attatched]]&lt;br /&gt;
This wiki describes how to wire a [http://www.sparkfun.com/commerce/product_info.php?products_id=691 nRF24L01+ chip] (&amp;quot;wireless chip&amp;quot;) to a PIC32 board and includes annotated code describing the functions that facilitate the transmitting and receiving of wireless data. A  [[media:Wireless-ppt.pdf|PowerPoint presentation]] covering much of the introductory information available on this page is also available. &lt;br /&gt;
&lt;br /&gt;
To operate the system, you must properly connect the wireless chips to the PIC32s, load the transmitter code onto the PIC that you wish to act as a transmitter, load the receiver code onto the PIC that you wish to act as a receiver, properly connect an RS232 cable to the PIC and open a serial communication program (e.g. HyperTerminal or [http://chiark.greenend.org.uk/~sgtatham/putty/download.html putty]), and turn the NU32 boards on. If you use the c-files provided on this pages (and everything else is set up properly), the transmitting PIC will broadcast  any characters received from the PC via RS232, and the receiving PIC will display what it receives from wireless link on the PC via RS232. The payload width can be adjusted using the &amp;quot;[&amp;quot; and &amp;quot;]&amp;quot; keys on both the transmitting and receiving PICs. Both wireless chips must be set to the same payload width in order to communicate. Payload widths may vary from 1 to 32. The transmitting PIC will not transmit until enough characters have been entered to fill a payload. Once enough characters have been entered into the transmitting PIC, the serial display will move to a new line to signal transmission.&lt;br /&gt;
&lt;br /&gt;
==Chip Basics==&lt;br /&gt;
The nrf24L01+ Module is a breakout of the nrf24L01+ 2.4 GHz transceiver, with an on board antenna. In order to get a wireless link up and running, the following parameters must be consistent between a transmitter and receiver chip:&lt;br /&gt;
&lt;br /&gt;
===Channels===&lt;br /&gt;
The channel of the nrf24L01+ chip is the frequency that it broadcasts and receives data from. The channel can range from 2.4 GHz to 2.525 GHz, at intervals no more than 1 MHz. The exact distance between channels is dependent on the on air data rate. Two wireless chips must be tuned to the same channel in order to communicate.  See the Air Data Rate section for necessary channel spacing.&lt;br /&gt;
&lt;br /&gt;
===Air Data Rate===&lt;br /&gt;
The air data rate is the rate at which the chip transmits bits wirelessly (and the rate at which it looks for them). The nrf24L01+ chip has three selectable data rates: 250 kbps, 1 Mbps, and 2 Mbps. Faster data rates draw less current, but require a greater distance between channels. Slower data rates give you the option of more channels and better receiver sensitivity, for the obvious trade off of speed. Data rates of 250 kbps and 1 Mbps require channel spacing of at least 1 MHz (allowing for 125 unique channels), and a data rate of 2 Mbps requires spacing of 2 MHz between channels (allowing for 62 channels).  Two wireless chips will not be able to communicate if they are not set to the same on air data rate.&lt;br /&gt;
&lt;br /&gt;
===Payload Width===&lt;br /&gt;
The payload is the actual data you are trying to send over a wireless link, and the payload width is how many bytes are contained within each payload. The nfr24L01+ is capable of supporting payloads up to 32 bytes. A transmitter and receiver must be set to the same payload in order to communicate. Transmission speeds for different sizes payloads are analyzed below. &lt;br /&gt;
&lt;br /&gt;
===Addresses &amp;amp; Pipes===&lt;br /&gt;
Every wireless transmission is preceded by the address of the intended receiver. The nrf24L01+ chip has 6 different receiving pipes, which means it may act as 6 receivers with 6 different addresses. Addresses may be three, four, or five bytes long. The addresses for pipe 0 and 1 may be completely different, but the addresses for pipes 2, 3, and 4 may only differ from the address of pipe 1 by their least significant byte. All active pipes feed into the same 3-packet-deep  incoming transmission queue.  Each pipe may also be set to a expect a different payload width.&lt;br /&gt;
&lt;br /&gt;
== Circuit ==&lt;br /&gt;
&lt;br /&gt;
[[Image:Wireless-circuit.jpg|thumb|Schematic of the nRF24L01+ connected to the PIC32_NU32 board]]&lt;br /&gt;
&lt;br /&gt;
The nrf24L01+ chip has 8 pins that need to be wired to the PIC (all I/O are relative to PIC):&lt;br /&gt;
&lt;br /&gt;
*Vcc: +3.3 Vdc supply&amp;lt;br&amp;gt;&lt;br /&gt;
*CE:  uC pin C1 (input)&amp;lt;br&amp;gt;&lt;br /&gt;
*CSN: uC pin C2 (output) &amp;lt;br&amp;gt;&lt;br /&gt;
*SCK: uC pin D10, configured as SCK(SPI) (output)&amp;lt;br&amp;gt;&lt;br /&gt;
*MOSI: uC pin D0, configured as SDO(SPI) (output) &amp;lt;br&amp;gt;&lt;br /&gt;
*MISO: uC pin C4, configured as SDI(SPI) (input)&amp;lt;br&amp;gt;&lt;br /&gt;
*IRQ: uC pin B0 (input) &amp;lt;br&amp;gt;&lt;br /&gt;
*GND: common digital ground&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The +3.3V and ground are provided by the NU32 board. The term &amp;quot;uC&amp;quot; above stands for microcontroller, which is the PIC32 in our case. &lt;br /&gt;
&lt;br /&gt;
Descriptions of the wireless chip&amp;#039;s pins can be found in Brennan Ball&amp;#039;s DIYembedded [http://www.diyembedded.com/tutorials/nrf24l01_0/nrf24l01_tutorial_0.pdf Tutorial 0]. The SCK, MOSI, and MISO pins interface with the SPI on the PIC32 which allows for communication between the PIC and the wireless chip. The GPIO pins will be initialized as digital inputs or outputs in the code to enable/disable the wireless chip and check the wireless data transfer/receive stats.&lt;br /&gt;
&lt;br /&gt;
In order to print information from the PIC to the PC, we need to wire an [[PIC_RS232]] cable&amp;#039;s transfer and receive lines to the UART ports of the NU32 board (F4, F5).&lt;br /&gt;
&lt;br /&gt;
==Code==&lt;br /&gt;
&lt;br /&gt;
===Driver===&lt;br /&gt;
Besides the main C files for the transmitter and receiver, the project also needs the [[media:Wireless-files.zip|nRF24L01.h header file and C file]]. These driver files were created by Brennan Ball, and are explained in detail in his [http://blog.diyembedded.com/ tutorials]. The following things must be changed in the header file available on his website to make it compatible with the NU32 board:&lt;br /&gt;
*pin registers and masks must be set to the appropriate values&lt;br /&gt;
*the &amp;quot;HardwareProfile.h&amp;quot; NU32 specific file must be included &lt;br /&gt;
&lt;br /&gt;
These changes are accounted for the the driver available on this page. All of the SPI functions trace back to a single function to send and read a single byte, which must be defined in the main c file. &lt;br /&gt;
&lt;br /&gt;
This function is available here: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 unsigned char spi_send_read_byte(unsigned char byte) {&lt;br /&gt;
  	 unsigned short	txData, rxData; // transmit, receive characters&lt;br /&gt;
   	 int chn = 1; // SPI channel to use (1 or 2)&lt;br /&gt;
  	 &lt;br /&gt;
   	 txData = byte; // take inputted byte and store into txData   &lt;br /&gt;
   	 SpiChnPutC(chn, txData);			// send data&lt;br /&gt;
 	 rxData = SpiChnGetC(chn);			// retreive over channel chn the received data into rxData&lt;br /&gt;
    &lt;br /&gt;
  	 return rxData; &lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
===Initialization Functions===&lt;br /&gt;
In order to get a wireless link up and running, you will need to initialize both the wireless chip and SPI communication on the PIC. &lt;br /&gt;
To intialize SPI on the PIC, create the following function in your main C file:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;void SpiInitDevice(int chn, int isMaster, int frmEn, int frmMaster) {&lt;br /&gt;
   	 unsigned int config = SPI_CON_MODE8|SPI_CON_SMP|SPI_CON_ON;	// SPI configuration word&lt;br /&gt;
   	 if(isMaster)&lt;br /&gt;
   	 {&lt;br /&gt;
   		 config|=SPI_CON_MSTEN;&lt;br /&gt;
   	 }&lt;br /&gt;
   	 if(frmEn)&lt;br /&gt;
   	 {&lt;br /&gt;
   		 config|=SPI_CON_FRMEN;&lt;br /&gt;
   		 if(!frmMaster) {   &lt;br /&gt;
   			 config|=SPI_CON_FRMSYNC;&lt;br /&gt;
      	 }&lt;br /&gt;
   	 }&lt;br /&gt;
  	 SpiChnOpen(chn, config, 4);	// divide fpb by 4, configure the I/O ports. Not using SS in this example&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
You can then call this function with the call &amp;lt;code&amp;gt; SpiInitDevice(1,1,0,0) &amp;lt;/code&amp;gt; to initalize SPI channel 1 on the PIC. &lt;br /&gt;
&lt;br /&gt;
To initialize the nrf24L01+ chip itself, you have to options. You can either use &amp;lt;code&amp;gt; nrf24L01_initialize(..) &amp;lt;/code&amp;gt; which gives  you the opportunity to manually define every register in the chip right from the start. However, this function has 21 arguments, so it is not the most convenient to use if you don&amp;#039;t have to. Instead, you can use &amp;lt;code&amp;gt; nrf24L01_initialize_debug(bool rx, int width, bool auto_ack_on) &amp;lt;/code&amp;gt;, which gives you the option to specify whether or not the chip is a receiver or transmitter, what the payload width is, and whether or not to enable auto-acknowledge. However, it limits you to Pipe 0, an air data rate of 2 Mpbs, and RF Channel 2. However, these limitations can be adjusted easily after initialization using additional functions (see the library for all available functions). So, for example, to initialize your chip as a transmitter with a payload width of one byte and no auto-acknowledgement, you could call &amp;lt;code&amp;gt; nrf24L01_initialize_debug(0,1,0)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If you wish to display information to the screen or receive information from the keyboard, you will have to initialize the RS232 connection as well. This can be done with the following code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
int pbClk = SYSTEMConfigPerformance(SYS_FREQ);&lt;br /&gt;
initUART2(pbClk);&lt;br /&gt;
&lt;br /&gt;
 void initUART2(int pbClk) {&lt;br /&gt;
  	 #define config1 	UART_EN | UART_IDLE_CON | UART_RX_TX | UART_DIS_WAKE | UART_DIS_LOOPBACK | UART_DIS_ABAUD | UART_NO_PAR_8BIT | UART_1STOPBIT | UART_IRDA_DIS | UART_DIS_BCLK_CTS_RTS| UART_NORMAL_RX | UART_BRGH_SIXTEEN&lt;br /&gt;
  	 #define config2		UART_TX_PIN_LOW | UART_RX_ENABLE | UART_TX_ENABLE | UART_INT_TX | UART_INT_RX_CHAR | UART_ADR_DETECT_DIS | UART_RX_OVERRUN_CLEAR	&lt;br /&gt;
   	 OpenUART2( config1, config2, pbClk/16/DESIRED_BAUDRATE-1);	// calculate actual BAUD generate value.&lt;br /&gt;
   	 ConfigIntUART2(UART_INT_PR2 | UART_RX_INT_EN);&lt;br /&gt;
   	 //INTEnableSystemMultiVectoredInt(); //interrupts enabled?&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Transmitter Code===&lt;br /&gt;
&lt;br /&gt;
Wirelessly transmitting data requires three steps:&lt;br /&gt;
&lt;br /&gt;
*initialize nrf24L01+ as transmitter&lt;br /&gt;
*transmit packet&lt;br /&gt;
*wait for payload to be sent&lt;br /&gt;
&lt;br /&gt;
A basic outline for such a procedure would look like:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
char data = &amp;#039;x&amp;#039;; //data to send&lt;br /&gt;
int width = 1; //width of payload&lt;br /&gt;
&lt;br /&gt;
nrf24l01_initialize_debug(false, width, false); //initialize the 24L01 to the debug configuration as TX, 1  data byte, and auto-ack disabled&lt;br /&gt;
&lt;br /&gt;
nrf24l01_write_tx_payload(&amp;amp;data, width, true); //add char to Tx queue, and transmit immediately  (char * data, int width, bool transmit_now)&lt;br /&gt;
&lt;br /&gt;
while(!(nrf24l01_irq_pin_active() &amp;amp;&amp;amp; nrf24l01_irq_tx_ds_active())); //wait until IRQ status tells us that it is done transmitting&lt;br /&gt;
&lt;br /&gt;
nrf24l01_irq_clear_all(); //clear all interrupts in the 24L01&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A fully functional [[media:nrf-tx.c|transmitter c-file]] is available. It is intended to work with the receiving code file, available below, and allows for a variable payload.&lt;br /&gt;
&lt;br /&gt;
===Receiver Code===&lt;br /&gt;
Similarly, receiving data from a wireless link requires three steps:&lt;br /&gt;
*initialize nrf24L01+ as receiver&lt;br /&gt;
*wait for incoming packet&lt;br /&gt;
*write packet to memory&lt;br /&gt;
&lt;br /&gt;
That would look like: &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
char data; //variable to recieve incoming data&lt;br /&gt;
int width = 1; //width of payload&lt;br /&gt;
&lt;br /&gt;
nrf24l01_initialize_debug(true, width, false); //initialize the 24L01 to the debug configuration as RX, 1  data byte, and auto-ack disabled&lt;br /&gt;
&lt;br /&gt;
while(!(nrf24l01_irq_pin_active() &amp;amp;&amp;amp; nrf24l01_irq_rx_dr_active())); //wait to receive a packet&lt;br /&gt;
&lt;br /&gt;
nrf24l01_read_rx_payload(&amp;amp;data, width); //get the payload into data&lt;br /&gt;
&lt;br /&gt;
nrf24l01_irq_clear_all(); //clear interrupts&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A fully functional [[media:nrf-rx.c|receiver c-file]] is available. It is intended to work with the transmitter code file, available above, and allows for a variable payload.&lt;br /&gt;
&lt;br /&gt;
===Handling Multi-byte Payloads===&lt;br /&gt;
Transmitting and receiving payloads of widths larger than one byte are handled the same exact way as described as above, except that instead of having a a single char data variable, you would have an array of chars as your data variable. Then rather then pass in the memory of address of &amp;lt;code&amp;gt;data &amp;lt;/code&amp;gt; you can simply pass in &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt; itself,  because in C, the variable representing an array is synonymous with the memory address of its first element. Examples of this are available in the attached C files.&lt;br /&gt;
&lt;br /&gt;
===Bidirectional Communication===&lt;br /&gt;
While technically the nrf24l01+ chip can only be in one mode (transmitting/receiving) at a given instant, with some clever programming you can still get a bidirectional link established between two chips. The [[media:nrf-bidirectional.c| full code for bidirectional communication]] is available on this page. Basically, the chip sits in receiver mode, listening for any incoming packets. If it receives one, it displays it to the screen. However, there in the event that a key is pressed on the local terminal, the PIC switches the mode from receiving to transmitting, transmits the data received locally, and then goes back to receiver mode.   It is not a perfect system because if a packet reaches a chip while the chip is in the middle of transmitting a packet itself, it will not pick up the packet in the air. However, the chance of this sort of situation happening would be rare, depending on the application of the system. &lt;br /&gt;
&lt;br /&gt;
To establish a bidirectional link, both PICs should have the same bidirectional c-file loaded (but this is not necessary: e.g. one PIC could only be able to transmit, and it would still be a viable one-way link ). If the on air data rate is set to 1 Mbps, then this bidirectional c-file is compatible with the [http://www.sparkfun.com/commerce/product_info.php?products_id=9019 Nordic USB Serial Converter] (note that the Nordic USB-Serial converter is only compatible with a payload width of four bytes). The payload width of the bidirectional link can be adjusted with the &amp;quot;[&amp;quot; and &amp;quot;]&amp;quot; keys, exactly as with the above code.&lt;br /&gt;
&lt;br /&gt;
==Latency and Data Rates==&lt;br /&gt;
&lt;br /&gt;
Basic timed tests were done to find out how long it took to transmit and receive different sized payloads, as well as the latency involved with transmission.&lt;br /&gt;
&lt;br /&gt;
===Latency===&lt;br /&gt;
To measure transmission latency, an oscilloscope was used to time how long it took before transmission was complete. For instance, something like this was used:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
while(1){&lt;br /&gt;
	if (!swUser){&lt;br /&gt;
			PIN_D1=1; //raise test pin&lt;br /&gt;
&lt;br /&gt;
			nrf24l01_write_tx_payload(dataToSend, width, true); //transmit char array over RF&lt;br /&gt;
			&lt;br /&gt;
			//wait until the packet has been sent&lt;br /&gt;
			while(!(nrf24l01_irq_pin_active() &amp;amp;&amp;amp; nrf24l01_irq_tx_ds_active()));&lt;br /&gt;
&lt;br /&gt;
			PIN_D1=0; //lower test pin&lt;br /&gt;
			nrf24l01_irq_clear_all(); //clear all interrupts in the 24L01&lt;br /&gt;
          }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Three measurements of time to transmit were done for each payload size. It should be noted that these results are completely independent of whether or not the transmission successfully made it to a receiver; in fact, these tests were done without a receiving PIC. The results seem to indicate a latency of 178 microseconds.&lt;br /&gt;
 [[Image:nrf-latency.jpg|thumb|Plot of Transmission Latency]]&lt;br /&gt;
&lt;br /&gt;
These tests were done by sending a packet wirelessly, then timing how long it took to get it back. A pin was raised to high while waiting and then dropped when it was received. These periods were then measured on an oscilloscope, and then averaged. The times used were only those that had 100% return rate. However, the accuracy of these packets was not checked beyond the built in CRC error-checking within the packets themselves. The rates here are to go send out a transmission and then receive it back, so the rate should be doubled for only transmitting in one direction.&lt;br /&gt;
[[Image:bps-nrf24l01.jpg|tumb|Plot of Data Rates]]&lt;/div&gt;</summary>
		<author><name>AndrewKessler</name></author>
	</entry>
	<entry>
		<id>https://hades.mech.northwestern.edu//index.php?title=File:Nrf-latency.jpg&amp;diff=19034</id>
		<title>File:Nrf-latency.jpg</title>
		<link rel="alternate" type="text/html" href="https://hades.mech.northwestern.edu//index.php?title=File:Nrf-latency.jpg&amp;diff=19034"/>
		<updated>2010-09-17T16:04:15Z</updated>

		<summary type="html">&lt;p&gt;AndrewKessler: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>AndrewKessler</name></author>
	</entry>
	<entry>
		<id>https://hades.mech.northwestern.edu//index.php?title=PIC32MX:_High-speed_Wireless_Communication&amp;diff=19033</id>
		<title>PIC32MX: High-speed Wireless Communication</title>
		<link rel="alternate" type="text/html" href="https://hades.mech.northwestern.edu//index.php?title=PIC32MX:_High-speed_Wireless_Communication&amp;diff=19033"/>
		<updated>2010-09-17T16:03:53Z</updated>

		<summary type="html">&lt;p&gt;AndrewKessler: /* Latency */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Overview ==&lt;br /&gt;
&lt;br /&gt;
[[Image:nrf-pic1.jpg|thumb|nrf24L01+ wireless chip with pins attatched]]&lt;br /&gt;
This wiki describes how to wire a [http://www.sparkfun.com/commerce/product_info.php?products_id=691 nRF24L01+ chip] (&amp;quot;wireless chip&amp;quot;) to a PIC32 board and includes annotated code describing the functions that facilitate the transmitting and receiving of wireless data. A  [[media:Wireless-ppt.pdf|PowerPoint presentation]] covering much of the introductory information available on this page is also available. &lt;br /&gt;
&lt;br /&gt;
To operate the system, you must properly connect the wireless chips to the PIC32s, load the transmitter code onto the PIC that you wish to act as a transmitter, load the receiver code onto the PIC that you wish to act as a receiver, properly connect an RS232 cable to the PIC and open a serial communication program (e.g. HyperTerminal or [http://chiark.greenend.org.uk/~sgtatham/putty/download.html putty]), and turn the NU32 boards on. If you use the c-files provided on this pages (and everything else is set up properly), the transmitting PIC will broadcast  any characters received from the PC via RS232, and the receiving PIC will display what it receives from wireless link on the PC via RS232. The payload width can be adjusted using the &amp;quot;[&amp;quot; and &amp;quot;]&amp;quot; keys on both the transmitting and receiving PICs. Both wireless chips must be set to the same payload width in order to communicate. Payload widths may vary from 1 to 32. The transmitting PIC will not transmit until enough characters have been entered to fill a payload. Once enough characters have been entered into the transmitting PIC, the serial display will move to a new line to signal transmission.&lt;br /&gt;
&lt;br /&gt;
==Chip Basics==&lt;br /&gt;
The nrf24L01+ Module is a breakout of the nrf24L01+ 2.4 GHz transceiver, with an on board antenna. In order to get a wireless link up and running, the following parameters must be consistent between a transmitter and receiver chip:&lt;br /&gt;
&lt;br /&gt;
===Channels===&lt;br /&gt;
The channel of the nrf24L01+ chip is the frequency that it broadcasts and receives data from. The channel can range from 2.4 GHz to 2.525 GHz, at intervals no more than 1 MHz. The exact distance between channels is dependent on the on air data rate. Two wireless chips must be tuned to the same channel in order to communicate.  See the Air Data Rate section for necessary channel spacing.&lt;br /&gt;
&lt;br /&gt;
===Air Data Rate===&lt;br /&gt;
The air data rate is the rate at which the chip transmits bits wirelessly (and the rate at which it looks for them). The nrf24L01+ chip has three selectable data rates: 250 kbps, 1 Mbps, and 2 Mbps. Faster data rates draw less current, but require a greater distance between channels. Slower data rates give you the option of more channels and better receiver sensitivity, for the obvious trade off of speed. Data rates of 250 kbps and 1 Mbps require channel spacing of at least 1 MHz (allowing for 125 unique channels), and a data rate of 2 Mbps requires spacing of 2 MHz between channels (allowing for 62 channels).  Two wireless chips will not be able to communicate if they are not set to the same on air data rate.&lt;br /&gt;
&lt;br /&gt;
===Payload Width===&lt;br /&gt;
The payload is the actual data you are trying to send over a wireless link, and the payload width is how many bytes are contained within each payload. The nfr24L01+ is capable of supporting payloads up to 32 bytes. A transmitter and receiver must be set to the same payload in order to communicate. Transmission speeds for different sizes payloads are analyzed below. &lt;br /&gt;
&lt;br /&gt;
===Addresses &amp;amp; Pipes===&lt;br /&gt;
Every wireless transmission is preceded by the address of the intended receiver. The nrf24L01+ chip has 6 different receiving pipes, which means it may act as 6 receivers with 6 different addresses. Addresses may be three, four, or five bytes long. The addresses for pipe 0 and 1 may be completely different, but the addresses for pipes 2, 3, and 4 may only differ from the address of pipe 1 by their least significant byte. All active pipes feed into the same 3-packet-deep  incoming transmission queue.  Each pipe may also be set to a expect a different payload width.&lt;br /&gt;
&lt;br /&gt;
== Circuit ==&lt;br /&gt;
&lt;br /&gt;
[[Image:Wireless-circuit.jpg|thumb|Schematic of the nRF24L01+ connected to the PIC32_NU32 board]]&lt;br /&gt;
&lt;br /&gt;
The nrf24L01+ chip has 8 pins that need to be wired to the PIC (all I/O are relative to PIC):&lt;br /&gt;
&lt;br /&gt;
*Vcc: +3.3 Vdc supply&amp;lt;br&amp;gt;&lt;br /&gt;
*CE:  uC pin C1 (input)&amp;lt;br&amp;gt;&lt;br /&gt;
*CSN: uC pin C2 (output) &amp;lt;br&amp;gt;&lt;br /&gt;
*SCK: uC pin D10, configured as SCK(SPI) (output)&amp;lt;br&amp;gt;&lt;br /&gt;
*MOSI: uC pin D0, configured as SDO(SPI) (output) &amp;lt;br&amp;gt;&lt;br /&gt;
*MISO: uC pin C4, configured as SDI(SPI) (input)&amp;lt;br&amp;gt;&lt;br /&gt;
*IRQ: uC pin B0 (input) &amp;lt;br&amp;gt;&lt;br /&gt;
*GND: common digital ground&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The +3.3V and ground are provided by the NU32 board. The term &amp;quot;uC&amp;quot; above stands for microcontroller, which is the PIC32 in our case. &lt;br /&gt;
&lt;br /&gt;
Descriptions of the wireless chip&amp;#039;s pins can be found in Brennan Ball&amp;#039;s DIYembedded [http://www.diyembedded.com/tutorials/nrf24l01_0/nrf24l01_tutorial_0.pdf Tutorial 0]. The SCK, MOSI, and MISO pins interface with the SPI on the PIC32 which allows for communication between the PIC and the wireless chip. The GPIO pins will be initialized as digital inputs or outputs in the code to enable/disable the wireless chip and check the wireless data transfer/receive stats.&lt;br /&gt;
&lt;br /&gt;
In order to print information from the PIC to the PC, we need to wire an [[PIC_RS232]] cable&amp;#039;s transfer and receive lines to the UART ports of the NU32 board (F4, F5).&lt;br /&gt;
&lt;br /&gt;
==Code==&lt;br /&gt;
&lt;br /&gt;
===Driver===&lt;br /&gt;
Besides the main C files for the transmitter and receiver, the project also needs the [[media:Wireless-files.zip|nRF24L01.h header file and C file]]. These driver files were created by Brennan Ball, and are explained in detail in his [http://blog.diyembedded.com/ tutorials]. The following things must be changed in the header file available on his website to make it compatible with the NU32 board:&lt;br /&gt;
*pin registers and masks must be set to the appropriate values&lt;br /&gt;
*the &amp;quot;HardwareProfile.h&amp;quot; NU32 specific file must be included &lt;br /&gt;
&lt;br /&gt;
These changes are accounted for the the driver available on this page. All of the SPI functions trace back to a single function to send and read a single byte, which must be defined in the main c file. &lt;br /&gt;
&lt;br /&gt;
This function is available here: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 unsigned char spi_send_read_byte(unsigned char byte) {&lt;br /&gt;
  	 unsigned short	txData, rxData; // transmit, receive characters&lt;br /&gt;
   	 int chn = 1; // SPI channel to use (1 or 2)&lt;br /&gt;
  	 &lt;br /&gt;
   	 txData = byte; // take inputted byte and store into txData   &lt;br /&gt;
   	 SpiChnPutC(chn, txData);			// send data&lt;br /&gt;
 	 rxData = SpiChnGetC(chn);			// retreive over channel chn the received data into rxData&lt;br /&gt;
    &lt;br /&gt;
  	 return rxData; &lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
===Initialization Functions===&lt;br /&gt;
In order to get a wireless link up and running, you will need to initialize both the wireless chip and SPI communication on the PIC. &lt;br /&gt;
To intialize SPI on the PIC, create the following function in your main C file:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;void SpiInitDevice(int chn, int isMaster, int frmEn, int frmMaster) {&lt;br /&gt;
   	 unsigned int config = SPI_CON_MODE8|SPI_CON_SMP|SPI_CON_ON;	// SPI configuration word&lt;br /&gt;
   	 if(isMaster)&lt;br /&gt;
   	 {&lt;br /&gt;
   		 config|=SPI_CON_MSTEN;&lt;br /&gt;
   	 }&lt;br /&gt;
   	 if(frmEn)&lt;br /&gt;
   	 {&lt;br /&gt;
   		 config|=SPI_CON_FRMEN;&lt;br /&gt;
   		 if(!frmMaster) {   &lt;br /&gt;
   			 config|=SPI_CON_FRMSYNC;&lt;br /&gt;
      	 }&lt;br /&gt;
   	 }&lt;br /&gt;
  	 SpiChnOpen(chn, config, 4);	// divide fpb by 4, configure the I/O ports. Not using SS in this example&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
You can then call this function with the call &amp;lt;code&amp;gt; SpiInitDevice(1,1,0,0) &amp;lt;/code&amp;gt; to initalize SPI channel 1 on the PIC. &lt;br /&gt;
&lt;br /&gt;
To initialize the nrf24L01+ chip itself, you have to options. You can either use &amp;lt;code&amp;gt; nrf24L01_initialize(..) &amp;lt;/code&amp;gt; which gives  you the opportunity to manually define every register in the chip right from the start. However, this function has 21 arguments, so it is not the most convenient to use if you don&amp;#039;t have to. Instead, you can use &amp;lt;code&amp;gt; nrf24L01_initialize_debug(bool rx, int width, bool auto_ack_on) &amp;lt;/code&amp;gt;, which gives you the option to specify whether or not the chip is a receiver or transmitter, what the payload width is, and whether or not to enable auto-acknowledge. However, it limits you to Pipe 0, an air data rate of 2 Mpbs, and RF Channel 2. However, these limitations can be adjusted easily after initialization using additional functions (see the library for all available functions). So, for example, to initialize your chip as a transmitter with a payload width of one byte and no auto-acknowledgement, you could call &amp;lt;code&amp;gt; nrf24L01_initialize_debug(0,1,0)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If you wish to display information to the screen or receive information from the keyboard, you will have to initialize the RS232 connection as well. This can be done with the following code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
int pbClk = SYSTEMConfigPerformance(SYS_FREQ);&lt;br /&gt;
initUART2(pbClk);&lt;br /&gt;
&lt;br /&gt;
 void initUART2(int pbClk) {&lt;br /&gt;
  	 #define config1 	UART_EN | UART_IDLE_CON | UART_RX_TX | UART_DIS_WAKE | UART_DIS_LOOPBACK | UART_DIS_ABAUD | UART_NO_PAR_8BIT | UART_1STOPBIT | UART_IRDA_DIS | UART_DIS_BCLK_CTS_RTS| UART_NORMAL_RX | UART_BRGH_SIXTEEN&lt;br /&gt;
  	 #define config2		UART_TX_PIN_LOW | UART_RX_ENABLE | UART_TX_ENABLE | UART_INT_TX | UART_INT_RX_CHAR | UART_ADR_DETECT_DIS | UART_RX_OVERRUN_CLEAR	&lt;br /&gt;
   	 OpenUART2( config1, config2, pbClk/16/DESIRED_BAUDRATE-1);	// calculate actual BAUD generate value.&lt;br /&gt;
   	 ConfigIntUART2(UART_INT_PR2 | UART_RX_INT_EN);&lt;br /&gt;
   	 //INTEnableSystemMultiVectoredInt(); //interrupts enabled?&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Transmitter Code===&lt;br /&gt;
&lt;br /&gt;
Wirelessly transmitting data requires three steps:&lt;br /&gt;
&lt;br /&gt;
*initialize nrf24L01+ as transmitter&lt;br /&gt;
*transmit packet&lt;br /&gt;
*wait for payload to be sent&lt;br /&gt;
&lt;br /&gt;
A basic outline for such a procedure would look like:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
char data = &amp;#039;x&amp;#039;; //data to send&lt;br /&gt;
int width = 1; //width of payload&lt;br /&gt;
&lt;br /&gt;
nrf24l01_initialize_debug(false, width, false); //initialize the 24L01 to the debug configuration as TX, 1  data byte, and auto-ack disabled&lt;br /&gt;
&lt;br /&gt;
nrf24l01_write_tx_payload(&amp;amp;data, width, true); //add char to Tx queue, and transmit immediately  (char * data, int width, bool transmit_now)&lt;br /&gt;
&lt;br /&gt;
while(!(nrf24l01_irq_pin_active() &amp;amp;&amp;amp; nrf24l01_irq_tx_ds_active())); //wait until IRQ status tells us that it is done transmitting&lt;br /&gt;
&lt;br /&gt;
nrf24l01_irq_clear_all(); //clear all interrupts in the 24L01&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A fully functional [[media:nrf-tx.c|transmitter c-file]] is available. It is intended to work with the receiving code file, available below, and allows for a variable payload.&lt;br /&gt;
&lt;br /&gt;
===Receiver Code===&lt;br /&gt;
Similarly, receiving data from a wireless link requires three steps:&lt;br /&gt;
*initialize nrf24L01+ as receiver&lt;br /&gt;
*wait for incoming packet&lt;br /&gt;
*write packet to memory&lt;br /&gt;
&lt;br /&gt;
That would look like: &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
char data; //variable to recieve incoming data&lt;br /&gt;
int width = 1; //width of payload&lt;br /&gt;
&lt;br /&gt;
nrf24l01_initialize_debug(true, width, false); //initialize the 24L01 to the debug configuration as RX, 1  data byte, and auto-ack disabled&lt;br /&gt;
&lt;br /&gt;
while(!(nrf24l01_irq_pin_active() &amp;amp;&amp;amp; nrf24l01_irq_rx_dr_active())); //wait to receive a packet&lt;br /&gt;
&lt;br /&gt;
nrf24l01_read_rx_payload(&amp;amp;data, width); //get the payload into data&lt;br /&gt;
&lt;br /&gt;
nrf24l01_irq_clear_all(); //clear interrupts&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A fully functional [[media:nrf-rx.c|receiver c-file]] is available. It is intended to work with the transmitter code file, available above, and allows for a variable payload.&lt;br /&gt;
&lt;br /&gt;
===Handling Multi-byte Payloads===&lt;br /&gt;
Transmitting and receiving payloads of widths larger than one byte are handled the same exact way as described as above, except that instead of having a a single char data variable, you would have an array of chars as your data variable. Then rather then pass in the memory of address of &amp;lt;code&amp;gt;data &amp;lt;/code&amp;gt; you can simply pass in &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt; itself,  because in C, the variable representing an array is synonymous with the memory address of its first element. Examples of this are available in the attached C files.&lt;br /&gt;
&lt;br /&gt;
===Bidirectional Communication===&lt;br /&gt;
While technically the nrf24l01+ chip can only be in one mode (transmitting/receiving) at a given instant, with some clever programming you can still get a bidirectional link established between two chips. The [[media:nrf-bidirectional.c| full code for bidirectional communication]] is available on this page. Basically, the chip sits in receiver mode, listening for any incoming packets. If it receives one, it displays it to the screen. However, there in the event that a key is pressed on the local terminal, the PIC switches the mode from receiving to transmitting, transmits the data received locally, and then goes back to receiver mode.   It is not a perfect system because if a packet reaches a chip while the chip is in the middle of transmitting a packet itself, it will not pick up the packet in the air. However, the chance of this sort of situation happening would be rare, depending on the application of the system. &lt;br /&gt;
&lt;br /&gt;
To establish a bidirectional link, both PICs should have the same bidirectional c-file loaded (but this is not necessary: e.g. one PIC could only be able to transmit, and it would still be a viable one-way link ). If the on air data rate is set to 1 Mbps, then this bidirectional c-file is compatible with the [http://www.sparkfun.com/commerce/product_info.php?products_id=9019 Nordic USB Serial Converter] (note that the Nordic USB-Serial converter is only compatible with a payload width of four bytes). The payload width of the bidirectional link can be adjusted with the &amp;quot;[&amp;quot; and &amp;quot;]&amp;quot; keys, exactly as with the above code.&lt;br /&gt;
&lt;br /&gt;
==Latency and Data Rates==&lt;br /&gt;
&lt;br /&gt;
Basic timed tests were done to find out how long it took to transmit and receive different sized payloads, as well as the latency involved with transmission.&lt;br /&gt;
&lt;br /&gt;
===Latency===&lt;br /&gt;
To measure transmission latency, an oscilloscope was used to time how long it took before transmission was complete. For instance, something like this was used:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
while(1){&lt;br /&gt;
	if (!swUser){&lt;br /&gt;
			PIN_D1=1; //raise test pin&lt;br /&gt;
&lt;br /&gt;
			nrf24l01_write_tx_payload(dataToSend, width, true); //transmit char array over RF&lt;br /&gt;
			&lt;br /&gt;
			//wait until the packet has been sent&lt;br /&gt;
			while(!(nrf24l01_irq_pin_active() &amp;amp;&amp;amp; nrf24l01_irq_tx_ds_active()));&lt;br /&gt;
&lt;br /&gt;
			PIN_D1=0; //lower test pin&lt;br /&gt;
			nrf24l01_irq_clear_all(); //clear all interrupts in the 24L01&lt;br /&gt;
          }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Three measurements of time to transmit were done for each payload size. It should be noted that these results are completely independent of whether or not the transmission successfully made it to a receiver; in fact, these tests were done without a receiving PIC. The results seem to indicate a latency of 178 microseconds.&lt;br /&gt;
 [[Image:nrf-latency.jpg|center]]&lt;br /&gt;
&lt;br /&gt;
These tests were done by sending a packet wirelessly, then timing how long it took to get it back. A pin was raised to high while waiting and then dropped when it was received. These periods were then measured on an oscilloscope, and then averaged. The times used were only those that had 100% return rate. However, the accuracy of these packets was not checked beyond the built in CRC error-checking within the packets themselves. The rates here are to go send out a transmission and then receive it back, so the rate should be doubled for only transmitting in one direction.&lt;br /&gt;
[[Image:bps-nrf24l01.jpg|center]]&lt;/div&gt;</summary>
		<author><name>AndrewKessler</name></author>
	</entry>
	<entry>
		<id>https://hades.mech.northwestern.edu//index.php?title=PIC32MX:_High-speed_Wireless_Communication&amp;diff=19032</id>
		<title>PIC32MX: High-speed Wireless Communication</title>
		<link rel="alternate" type="text/html" href="https://hades.mech.northwestern.edu//index.php?title=PIC32MX:_High-speed_Wireless_Communication&amp;diff=19032"/>
		<updated>2010-09-17T15:57:54Z</updated>

		<summary type="html">&lt;p&gt;AndrewKessler: /* Data Rates */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Overview ==&lt;br /&gt;
&lt;br /&gt;
[[Image:nrf-pic1.jpg|thumb|nrf24L01+ wireless chip with pins attatched]]&lt;br /&gt;
This wiki describes how to wire a [http://www.sparkfun.com/commerce/product_info.php?products_id=691 nRF24L01+ chip] (&amp;quot;wireless chip&amp;quot;) to a PIC32 board and includes annotated code describing the functions that facilitate the transmitting and receiving of wireless data. A  [[media:Wireless-ppt.pdf|PowerPoint presentation]] covering much of the introductory information available on this page is also available. &lt;br /&gt;
&lt;br /&gt;
To operate the system, you must properly connect the wireless chips to the PIC32s, load the transmitter code onto the PIC that you wish to act as a transmitter, load the receiver code onto the PIC that you wish to act as a receiver, properly connect an RS232 cable to the PIC and open a serial communication program (e.g. HyperTerminal or [http://chiark.greenend.org.uk/~sgtatham/putty/download.html putty]), and turn the NU32 boards on. If you use the c-files provided on this pages (and everything else is set up properly), the transmitting PIC will broadcast  any characters received from the PC via RS232, and the receiving PIC will display what it receives from wireless link on the PC via RS232. The payload width can be adjusted using the &amp;quot;[&amp;quot; and &amp;quot;]&amp;quot; keys on both the transmitting and receiving PICs. Both wireless chips must be set to the same payload width in order to communicate. Payload widths may vary from 1 to 32. The transmitting PIC will not transmit until enough characters have been entered to fill a payload. Once enough characters have been entered into the transmitting PIC, the serial display will move to a new line to signal transmission.&lt;br /&gt;
&lt;br /&gt;
==Chip Basics==&lt;br /&gt;
The nrf24L01+ Module is a breakout of the nrf24L01+ 2.4 GHz transceiver, with an on board antenna. In order to get a wireless link up and running, the following parameters must be consistent between a transmitter and receiver chip:&lt;br /&gt;
&lt;br /&gt;
===Channels===&lt;br /&gt;
The channel of the nrf24L01+ chip is the frequency that it broadcasts and receives data from. The channel can range from 2.4 GHz to 2.525 GHz, at intervals no more than 1 MHz. The exact distance between channels is dependent on the on air data rate. Two wireless chips must be tuned to the same channel in order to communicate.  See the Air Data Rate section for necessary channel spacing.&lt;br /&gt;
&lt;br /&gt;
===Air Data Rate===&lt;br /&gt;
The air data rate is the rate at which the chip transmits bits wirelessly (and the rate at which it looks for them). The nrf24L01+ chip has three selectable data rates: 250 kbps, 1 Mbps, and 2 Mbps. Faster data rates draw less current, but require a greater distance between channels. Slower data rates give you the option of more channels and better receiver sensitivity, for the obvious trade off of speed. Data rates of 250 kbps and 1 Mbps require channel spacing of at least 1 MHz (allowing for 125 unique channels), and a data rate of 2 Mbps requires spacing of 2 MHz between channels (allowing for 62 channels).  Two wireless chips will not be able to communicate if they are not set to the same on air data rate.&lt;br /&gt;
&lt;br /&gt;
===Payload Width===&lt;br /&gt;
The payload is the actual data you are trying to send over a wireless link, and the payload width is how many bytes are contained within each payload. The nfr24L01+ is capable of supporting payloads up to 32 bytes. A transmitter and receiver must be set to the same payload in order to communicate. Transmission speeds for different sizes payloads are analyzed below. &lt;br /&gt;
&lt;br /&gt;
===Addresses &amp;amp; Pipes===&lt;br /&gt;
Every wireless transmission is preceded by the address of the intended receiver. The nrf24L01+ chip has 6 different receiving pipes, which means it may act as 6 receivers with 6 different addresses. Addresses may be three, four, or five bytes long. The addresses for pipe 0 and 1 may be completely different, but the addresses for pipes 2, 3, and 4 may only differ from the address of pipe 1 by their least significant byte. All active pipes feed into the same 3-packet-deep  incoming transmission queue.  Each pipe may also be set to a expect a different payload width.&lt;br /&gt;
&lt;br /&gt;
== Circuit ==&lt;br /&gt;
&lt;br /&gt;
[[Image:Wireless-circuit.jpg|thumb|Schematic of the nRF24L01+ connected to the PIC32_NU32 board]]&lt;br /&gt;
&lt;br /&gt;
The nrf24L01+ chip has 8 pins that need to be wired to the PIC (all I/O are relative to PIC):&lt;br /&gt;
&lt;br /&gt;
*Vcc: +3.3 Vdc supply&amp;lt;br&amp;gt;&lt;br /&gt;
*CE:  uC pin C1 (input)&amp;lt;br&amp;gt;&lt;br /&gt;
*CSN: uC pin C2 (output) &amp;lt;br&amp;gt;&lt;br /&gt;
*SCK: uC pin D10, configured as SCK(SPI) (output)&amp;lt;br&amp;gt;&lt;br /&gt;
*MOSI: uC pin D0, configured as SDO(SPI) (output) &amp;lt;br&amp;gt;&lt;br /&gt;
*MISO: uC pin C4, configured as SDI(SPI) (input)&amp;lt;br&amp;gt;&lt;br /&gt;
*IRQ: uC pin B0 (input) &amp;lt;br&amp;gt;&lt;br /&gt;
*GND: common digital ground&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The +3.3V and ground are provided by the NU32 board. The term &amp;quot;uC&amp;quot; above stands for microcontroller, which is the PIC32 in our case. &lt;br /&gt;
&lt;br /&gt;
Descriptions of the wireless chip&amp;#039;s pins can be found in Brennan Ball&amp;#039;s DIYembedded [http://www.diyembedded.com/tutorials/nrf24l01_0/nrf24l01_tutorial_0.pdf Tutorial 0]. The SCK, MOSI, and MISO pins interface with the SPI on the PIC32 which allows for communication between the PIC and the wireless chip. The GPIO pins will be initialized as digital inputs or outputs in the code to enable/disable the wireless chip and check the wireless data transfer/receive stats.&lt;br /&gt;
&lt;br /&gt;
In order to print information from the PIC to the PC, we need to wire an [[PIC_RS232]] cable&amp;#039;s transfer and receive lines to the UART ports of the NU32 board (F4, F5).&lt;br /&gt;
&lt;br /&gt;
==Code==&lt;br /&gt;
&lt;br /&gt;
===Driver===&lt;br /&gt;
Besides the main C files for the transmitter and receiver, the project also needs the [[media:Wireless-files.zip|nRF24L01.h header file and C file]]. These driver files were created by Brennan Ball, and are explained in detail in his [http://blog.diyembedded.com/ tutorials]. The following things must be changed in the header file available on his website to make it compatible with the NU32 board:&lt;br /&gt;
*pin registers and masks must be set to the appropriate values&lt;br /&gt;
*the &amp;quot;HardwareProfile.h&amp;quot; NU32 specific file must be included &lt;br /&gt;
&lt;br /&gt;
These changes are accounted for the the driver available on this page. All of the SPI functions trace back to a single function to send and read a single byte, which must be defined in the main c file. &lt;br /&gt;
&lt;br /&gt;
This function is available here: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 unsigned char spi_send_read_byte(unsigned char byte) {&lt;br /&gt;
  	 unsigned short	txData, rxData; // transmit, receive characters&lt;br /&gt;
   	 int chn = 1; // SPI channel to use (1 or 2)&lt;br /&gt;
  	 &lt;br /&gt;
   	 txData = byte; // take inputted byte and store into txData   &lt;br /&gt;
   	 SpiChnPutC(chn, txData);			// send data&lt;br /&gt;
 	 rxData = SpiChnGetC(chn);			// retreive over channel chn the received data into rxData&lt;br /&gt;
    &lt;br /&gt;
  	 return rxData; &lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
===Initialization Functions===&lt;br /&gt;
In order to get a wireless link up and running, you will need to initialize both the wireless chip and SPI communication on the PIC. &lt;br /&gt;
To intialize SPI on the PIC, create the following function in your main C file:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;void SpiInitDevice(int chn, int isMaster, int frmEn, int frmMaster) {&lt;br /&gt;
   	 unsigned int config = SPI_CON_MODE8|SPI_CON_SMP|SPI_CON_ON;	// SPI configuration word&lt;br /&gt;
   	 if(isMaster)&lt;br /&gt;
   	 {&lt;br /&gt;
   		 config|=SPI_CON_MSTEN;&lt;br /&gt;
   	 }&lt;br /&gt;
   	 if(frmEn)&lt;br /&gt;
   	 {&lt;br /&gt;
   		 config|=SPI_CON_FRMEN;&lt;br /&gt;
   		 if(!frmMaster) {   &lt;br /&gt;
   			 config|=SPI_CON_FRMSYNC;&lt;br /&gt;
      	 }&lt;br /&gt;
   	 }&lt;br /&gt;
  	 SpiChnOpen(chn, config, 4);	// divide fpb by 4, configure the I/O ports. Not using SS in this example&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
You can then call this function with the call &amp;lt;code&amp;gt; SpiInitDevice(1,1,0,0) &amp;lt;/code&amp;gt; to initalize SPI channel 1 on the PIC. &lt;br /&gt;
&lt;br /&gt;
To initialize the nrf24L01+ chip itself, you have to options. You can either use &amp;lt;code&amp;gt; nrf24L01_initialize(..) &amp;lt;/code&amp;gt; which gives  you the opportunity to manually define every register in the chip right from the start. However, this function has 21 arguments, so it is not the most convenient to use if you don&amp;#039;t have to. Instead, you can use &amp;lt;code&amp;gt; nrf24L01_initialize_debug(bool rx, int width, bool auto_ack_on) &amp;lt;/code&amp;gt;, which gives you the option to specify whether or not the chip is a receiver or transmitter, what the payload width is, and whether or not to enable auto-acknowledge. However, it limits you to Pipe 0, an air data rate of 2 Mpbs, and RF Channel 2. However, these limitations can be adjusted easily after initialization using additional functions (see the library for all available functions). So, for example, to initialize your chip as a transmitter with a payload width of one byte and no auto-acknowledgement, you could call &amp;lt;code&amp;gt; nrf24L01_initialize_debug(0,1,0)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If you wish to display information to the screen or receive information from the keyboard, you will have to initialize the RS232 connection as well. This can be done with the following code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
int pbClk = SYSTEMConfigPerformance(SYS_FREQ);&lt;br /&gt;
initUART2(pbClk);&lt;br /&gt;
&lt;br /&gt;
 void initUART2(int pbClk) {&lt;br /&gt;
  	 #define config1 	UART_EN | UART_IDLE_CON | UART_RX_TX | UART_DIS_WAKE | UART_DIS_LOOPBACK | UART_DIS_ABAUD | UART_NO_PAR_8BIT | UART_1STOPBIT | UART_IRDA_DIS | UART_DIS_BCLK_CTS_RTS| UART_NORMAL_RX | UART_BRGH_SIXTEEN&lt;br /&gt;
  	 #define config2		UART_TX_PIN_LOW | UART_RX_ENABLE | UART_TX_ENABLE | UART_INT_TX | UART_INT_RX_CHAR | UART_ADR_DETECT_DIS | UART_RX_OVERRUN_CLEAR	&lt;br /&gt;
   	 OpenUART2( config1, config2, pbClk/16/DESIRED_BAUDRATE-1);	// calculate actual BAUD generate value.&lt;br /&gt;
   	 ConfigIntUART2(UART_INT_PR2 | UART_RX_INT_EN);&lt;br /&gt;
   	 //INTEnableSystemMultiVectoredInt(); //interrupts enabled?&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Transmitter Code===&lt;br /&gt;
&lt;br /&gt;
Wirelessly transmitting data requires three steps:&lt;br /&gt;
&lt;br /&gt;
*initialize nrf24L01+ as transmitter&lt;br /&gt;
*transmit packet&lt;br /&gt;
*wait for payload to be sent&lt;br /&gt;
&lt;br /&gt;
A basic outline for such a procedure would look like:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
char data = &amp;#039;x&amp;#039;; //data to send&lt;br /&gt;
int width = 1; //width of payload&lt;br /&gt;
&lt;br /&gt;
nrf24l01_initialize_debug(false, width, false); //initialize the 24L01 to the debug configuration as TX, 1  data byte, and auto-ack disabled&lt;br /&gt;
&lt;br /&gt;
nrf24l01_write_tx_payload(&amp;amp;data, width, true); //add char to Tx queue, and transmit immediately  (char * data, int width, bool transmit_now)&lt;br /&gt;
&lt;br /&gt;
while(!(nrf24l01_irq_pin_active() &amp;amp;&amp;amp; nrf24l01_irq_tx_ds_active())); //wait until IRQ status tells us that it is done transmitting&lt;br /&gt;
&lt;br /&gt;
nrf24l01_irq_clear_all(); //clear all interrupts in the 24L01&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A fully functional [[media:nrf-tx.c|transmitter c-file]] is available. It is intended to work with the receiving code file, available below, and allows for a variable payload.&lt;br /&gt;
&lt;br /&gt;
===Receiver Code===&lt;br /&gt;
Similarly, receiving data from a wireless link requires three steps:&lt;br /&gt;
*initialize nrf24L01+ as receiver&lt;br /&gt;
*wait for incoming packet&lt;br /&gt;
*write packet to memory&lt;br /&gt;
&lt;br /&gt;
That would look like: &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
char data; //variable to recieve incoming data&lt;br /&gt;
int width = 1; //width of payload&lt;br /&gt;
&lt;br /&gt;
nrf24l01_initialize_debug(true, width, false); //initialize the 24L01 to the debug configuration as RX, 1  data byte, and auto-ack disabled&lt;br /&gt;
&lt;br /&gt;
while(!(nrf24l01_irq_pin_active() &amp;amp;&amp;amp; nrf24l01_irq_rx_dr_active())); //wait to receive a packet&lt;br /&gt;
&lt;br /&gt;
nrf24l01_read_rx_payload(&amp;amp;data, width); //get the payload into data&lt;br /&gt;
&lt;br /&gt;
nrf24l01_irq_clear_all(); //clear interrupts&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A fully functional [[media:nrf-rx.c|receiver c-file]] is available. It is intended to work with the transmitter code file, available above, and allows for a variable payload.&lt;br /&gt;
&lt;br /&gt;
===Handling Multi-byte Payloads===&lt;br /&gt;
Transmitting and receiving payloads of widths larger than one byte are handled the same exact way as described as above, except that instead of having a a single char data variable, you would have an array of chars as your data variable. Then rather then pass in the memory of address of &amp;lt;code&amp;gt;data &amp;lt;/code&amp;gt; you can simply pass in &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt; itself,  because in C, the variable representing an array is synonymous with the memory address of its first element. Examples of this are available in the attached C files.&lt;br /&gt;
&lt;br /&gt;
===Bidirectional Communication===&lt;br /&gt;
While technically the nrf24l01+ chip can only be in one mode (transmitting/receiving) at a given instant, with some clever programming you can still get a bidirectional link established between two chips. The [[media:nrf-bidirectional.c| full code for bidirectional communication]] is available on this page. Basically, the chip sits in receiver mode, listening for any incoming packets. If it receives one, it displays it to the screen. However, there in the event that a key is pressed on the local terminal, the PIC switches the mode from receiving to transmitting, transmits the data received locally, and then goes back to receiver mode.   It is not a perfect system because if a packet reaches a chip while the chip is in the middle of transmitting a packet itself, it will not pick up the packet in the air. However, the chance of this sort of situation happening would be rare, depending on the application of the system. &lt;br /&gt;
&lt;br /&gt;
To establish a bidirectional link, both PICs should have the same bidirectional c-file loaded (but this is not necessary: e.g. one PIC could only be able to transmit, and it would still be a viable one-way link ). If the on air data rate is set to 1 Mbps, then this bidirectional c-file is compatible with the [http://www.sparkfun.com/commerce/product_info.php?products_id=9019 Nordic USB Serial Converter] (note that the Nordic USB-Serial converter is only compatible with a payload width of four bytes). The payload width of the bidirectional link can be adjusted with the &amp;quot;[&amp;quot; and &amp;quot;]&amp;quot; keys, exactly as with the above code.&lt;br /&gt;
&lt;br /&gt;
==Latency and Data Rates==&lt;br /&gt;
&lt;br /&gt;
Basic timed tests were done to find out how long it took to transmit and receive different sized payloads, as well as the latency involved with transmission.&lt;br /&gt;
&lt;br /&gt;
===Latency===&lt;br /&gt;
To measure transmission latency, an oscilloscope was used to time how long it took before transmission was complete. For instance, something like:&lt;br /&gt;
[code][pre]&lt;br /&gt;
while(1){&lt;br /&gt;
	if (!swUser){&lt;br /&gt;
			PIN_D1=1; //raise test pin&lt;br /&gt;
&lt;br /&gt;
			nrf24l01_write_tx_payload(dataToSend, width, true); //transmit char array over RF&lt;br /&gt;
			&lt;br /&gt;
			//wait until the packet has been sent&lt;br /&gt;
			while(!(nrf24l01_irq_pin_active() &amp;amp;&amp;amp; nrf24l01_irq_tx_ds_active()));&lt;br /&gt;
&lt;br /&gt;
			PIN_D1=0; //lower test pin&lt;br /&gt;
			nrf24l01_irq_clear_all(); //clear all interrupts in the 24L01&lt;br /&gt;
[/code][/pre]&lt;br /&gt;
&lt;br /&gt;
 These tests were done by sending a packet wirelessly, then timing how long it took to get it back. A pin was raised to high while waiting and then dropped when it was received. These periods were then measured on an oscilloscope, and then averaged. The times used were only those that had 100% return rate. However, the accuracy of these packets was not checked beyond the built in CRC error-checking within the packets themselves. The rates here are to go send out a transmission and then receive it back, so the rate should be doubled for only transmitting in one direction.&lt;br /&gt;
[[Image:bps-nrf24l01.jpg|center]]&lt;/div&gt;</summary>
		<author><name>AndrewKessler</name></author>
	</entry>
	<entry>
		<id>https://hades.mech.northwestern.edu//index.php?title=PIC32MX:_High-speed_Wireless_Communication&amp;diff=19011</id>
		<title>PIC32MX: High-speed Wireless Communication</title>
		<link rel="alternate" type="text/html" href="https://hades.mech.northwestern.edu//index.php?title=PIC32MX:_High-speed_Wireless_Communication&amp;diff=19011"/>
		<updated>2010-08-26T21:41:17Z</updated>

		<summary type="html">&lt;p&gt;AndrewKessler: /* Circuit */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Overview ==&lt;br /&gt;
&lt;br /&gt;
[[Image:nrf-pic1.jpg|thumb|nrf24L01+ wireless chip with pins attatched]]&lt;br /&gt;
This wiki describes how to wire a [http://www.sparkfun.com/commerce/product_info.php?products_id=691 nRF24L01+ chip] (&amp;quot;wireless chip&amp;quot;) to a PIC32 board and includes annotated code describing the functions that facilitate the transmitting and receiving of wireless data. A  [[media:Wireless-ppt.pdf|PowerPoint presentation]] covering much of the introductory information available on this page is also available. &lt;br /&gt;
&lt;br /&gt;
To operate the system, you must properly connect the wireless chips to the PIC32s, load the transmitter code onto the PIC that you wish to act as a transmitter, load the receiver code onto the PIC that you wish to act as a receiver, properly connect an RS232 cable to the PIC and open a serial communication program (e.g. HyperTerminal or [http://chiark.greenend.org.uk/~sgtatham/putty/download.html putty]), and turn the NU32 boards on. If you use the c-files provided on this pages (and everything else is set up properly), the transmitting PIC will broadcast  any characters received from the PC via RS232, and the receiving PIC will display what it receives from wireless link on the PC via RS232. The payload width can be adjusted using the &amp;quot;[&amp;quot; and &amp;quot;]&amp;quot; keys on both the transmitting and receiving PICs. Both wireless chips must be set to the same payload width in order to communicate. Payload widths may vary from 1 to 32. The transmitting PIC will not transmit until enough characters have been entered to fill a payload. Once enough characters have been entered into the transmitting PIC, the serial display will move to a new line to signal transmission.&lt;br /&gt;
&lt;br /&gt;
==Chip Basics==&lt;br /&gt;
The nrf24L01+ Module is a breakout of the nrf24L01+ 2.4 GHz transceiver, with an on board antenna. In order to get a wireless link up and running, the following parameters must be consistent between a transmitter and receiver chip:&lt;br /&gt;
&lt;br /&gt;
===Channels===&lt;br /&gt;
The channel of the nrf24L01+ chip is the frequency that it broadcasts and receives data from. The channel can range from 2.4 GHz to 2.525 GHz, at intervals no more than 1 MHz. The exact distance between channels is dependent on the on air data rate. Two wireless chips must be tuned to the same channel in order to communicate.  See the Air Data Rate section for necessary channel spacing.&lt;br /&gt;
&lt;br /&gt;
===Air Data Rate===&lt;br /&gt;
The air data rate is the rate at which the chip transmits bits wirelessly (and the rate at which it looks for them). The nrf24L01+ chip has three selectable data rates: 250 kbps, 1 Mbps, and 2 Mbps. Faster data rates draw less current, but require a greater distance between channels. Slower data rates give you the option of more channels and better receiver sensitivity, for the obvious trade off of speed. Data rates of 250 kbps and 1 Mbps require channel spacing of at least 1 MHz (allowing for 125 unique channels), and a data rate of 2 Mbps requires spacing of 2 MHz between channels (allowing for 62 channels).  Two wireless chips will not be able to communicate if they are not set to the same on air data rate.&lt;br /&gt;
&lt;br /&gt;
===Payload Width===&lt;br /&gt;
The payload is the actual data you are trying to send over a wireless link, and the payload width is how many bytes are contained within each payload. The nfr24L01+ is capable of supporting payloads up to 32 bytes. A transmitter and receiver must be set to the same payload in order to communicate. Transmission speeds for different sizes payloads are analyzed below. &lt;br /&gt;
&lt;br /&gt;
===Addresses &amp;amp; Pipes===&lt;br /&gt;
Every wireless transmission is preceded by the address of the intended receiver. The nrf24L01+ chip has 6 different receiving pipes, which means it may act as 6 receivers with 6 different addresses. Addresses may be three, four, or five bytes long. The addresses for pipe 0 and 1 may be completely different, but the addresses for pipes 2, 3, and 4 may only differ from the address of pipe 1 by their least significant byte. All active pipes feed into the same 3-packet-deep  incoming transmission queue.  Each pipe may also be set to a expect a different payload width.&lt;br /&gt;
&lt;br /&gt;
== Circuit ==&lt;br /&gt;
&lt;br /&gt;
[[Image:Wireless-circuit.jpg|thumb|Schematic of the nRF24L01+ connected to the PIC32_NU32 board]]&lt;br /&gt;
&lt;br /&gt;
The nrf24L01+ chip has 8 pins that need to be wired to the PIC (all I/O are relative to PIC):&lt;br /&gt;
&lt;br /&gt;
*Vcc: +3.3 Vdc supply&amp;lt;br&amp;gt;&lt;br /&gt;
*CE:  uC pin C1 (input)&amp;lt;br&amp;gt;&lt;br /&gt;
*CSN: uC pin C2 (output) &amp;lt;br&amp;gt;&lt;br /&gt;
*SCK: uC pin D10, configured as SCK(SPI) (output)&amp;lt;br&amp;gt;&lt;br /&gt;
*MOSI: uC pin D0, configured as SDO(SPI) (output) &amp;lt;br&amp;gt;&lt;br /&gt;
*MISO: uC pin C4, configured as SDI(SPI) (input)&amp;lt;br&amp;gt;&lt;br /&gt;
*IRQ: uC pin B0 (input) &amp;lt;br&amp;gt;&lt;br /&gt;
*GND: common digital ground&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The +3.3V and ground are provided by the NU32 board. The term &amp;quot;uC&amp;quot; above stands for microcontroller, which is the PIC32 in our case. &lt;br /&gt;
&lt;br /&gt;
Descriptions of the wireless chip&amp;#039;s pins can be found in Brennan Ball&amp;#039;s DIYembedded [http://www.diyembedded.com/tutorials/nrf24l01_0/nrf24l01_tutorial_0.pdf Tutorial 0]. The SCK, MOSI, and MISO pins interface with the SPI on the PIC32 which allows for communication between the PIC and the wireless chip. The GPIO pins will be initialized as digital inputs or outputs in the code to enable/disable the wireless chip and check the wireless data transfer/receive stats.&lt;br /&gt;
&lt;br /&gt;
In order to print information from the PIC to the PC, we need to wire an [[PIC_RS232]] cable&amp;#039;s transfer and receive lines to the UART ports of the NU32 board (F4, F5).&lt;br /&gt;
&lt;br /&gt;
==Code==&lt;br /&gt;
&lt;br /&gt;
===Driver===&lt;br /&gt;
Besides the main C files for the transmitter and receiver, the project also needs the [[media:Wireless-files.zip|nRF24L01.h header file and C file]]. These driver files were created by Brennan Ball, and are explained in detail in his [http://blog.diyembedded.com/ tutorials]. The following things must be changed in the header file available on his website to make it compatible with the NU32 board:&lt;br /&gt;
*pin registers and masks must be set to the appropriate values&lt;br /&gt;
*the &amp;quot;HardwareProfile.h&amp;quot; NU32 specific file must be included &lt;br /&gt;
&lt;br /&gt;
These changes are accounted for the the driver available on this page. All of the SPI functions trace back to a single function to send and read a single byte, which must be defined in the main c file. &lt;br /&gt;
&lt;br /&gt;
This function is available here: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 unsigned char spi_send_read_byte(unsigned char byte) {&lt;br /&gt;
  	 unsigned short	txData, rxData; // transmit, receive characters&lt;br /&gt;
   	 int chn = 1; // SPI channel to use (1 or 2)&lt;br /&gt;
  	 &lt;br /&gt;
   	 txData = byte; // take inputted byte and store into txData   &lt;br /&gt;
   	 SpiChnPutC(chn, txData);			// send data&lt;br /&gt;
 	 rxData = SpiChnGetC(chn);			// retreive over channel chn the received data into rxData&lt;br /&gt;
    &lt;br /&gt;
  	 return rxData; &lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
===Initialization Functions===&lt;br /&gt;
In order to get a wireless link up and running, you will need to initialize both the wireless chip and SPI communication on the PIC. &lt;br /&gt;
To intialize SPI on the PIC, create the following function in your main C file:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;void SpiInitDevice(int chn, int isMaster, int frmEn, int frmMaster) {&lt;br /&gt;
   	 unsigned int config = SPI_CON_MODE8|SPI_CON_SMP|SPI_CON_ON;	// SPI configuration word&lt;br /&gt;
   	 if(isMaster)&lt;br /&gt;
   	 {&lt;br /&gt;
   		 config|=SPI_CON_MSTEN;&lt;br /&gt;
   	 }&lt;br /&gt;
   	 if(frmEn)&lt;br /&gt;
   	 {&lt;br /&gt;
   		 config|=SPI_CON_FRMEN;&lt;br /&gt;
   		 if(!frmMaster) {   &lt;br /&gt;
   			 config|=SPI_CON_FRMSYNC;&lt;br /&gt;
      	 }&lt;br /&gt;
   	 }&lt;br /&gt;
  	 SpiChnOpen(chn, config, 4);	// divide fpb by 4, configure the I/O ports. Not using SS in this example&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
You can then call this function with the call &amp;lt;code&amp;gt; SpiInitDevice(1,1,0,0) &amp;lt;/code&amp;gt; to initalize SPI channel 1 on the PIC. &lt;br /&gt;
&lt;br /&gt;
To initialize the nrf24L01+ chip itself, you have to options. You can either use &amp;lt;code&amp;gt; nrf24L01_initialize(..) &amp;lt;/code&amp;gt; which gives  you the opportunity to manually define every register in the chip right from the start. However, this function has 21 arguments, so it is not the most convenient to use if you don&amp;#039;t have to. Instead, you can use &amp;lt;code&amp;gt; nrf24L01_initialize_debug(bool rx, int width, bool auto_ack_on) &amp;lt;/code&amp;gt;, which gives you the option to specify whether or not the chip is a receiver or transmitter, what the payload width is, and whether or not to enable auto-acknowledge. However, it limits you to Pipe 0, an air data rate of 2 Mpbs, and RF Channel 2. However, these limitations can be adjusted easily after initialization using additional functions (see the library for all available functions). So, for example, to initialize your chip as a transmitter with a payload width of one byte and no auto-acknowledgement, you could call &amp;lt;code&amp;gt; nrf24L01_initialize_debug(0,1,0)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If you wish to display information to the screen or receive information from the keyboard, you will have to initialize the RS232 connection as well. This can be done with the following code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
int pbClk = SYSTEMConfigPerformance(SYS_FREQ);&lt;br /&gt;
initUART2(pbClk);&lt;br /&gt;
&lt;br /&gt;
 void initUART2(int pbClk) {&lt;br /&gt;
  	 #define config1 	UART_EN | UART_IDLE_CON | UART_RX_TX | UART_DIS_WAKE | UART_DIS_LOOPBACK | UART_DIS_ABAUD | UART_NO_PAR_8BIT | UART_1STOPBIT | UART_IRDA_DIS | UART_DIS_BCLK_CTS_RTS| UART_NORMAL_RX | UART_BRGH_SIXTEEN&lt;br /&gt;
  	 #define config2		UART_TX_PIN_LOW | UART_RX_ENABLE | UART_TX_ENABLE | UART_INT_TX | UART_INT_RX_CHAR | UART_ADR_DETECT_DIS | UART_RX_OVERRUN_CLEAR	&lt;br /&gt;
   	 OpenUART2( config1, config2, pbClk/16/DESIRED_BAUDRATE-1);	// calculate actual BAUD generate value.&lt;br /&gt;
   	 ConfigIntUART2(UART_INT_PR2 | UART_RX_INT_EN);&lt;br /&gt;
   	 //INTEnableSystemMultiVectoredInt(); //interrupts enabled?&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Transmitter Code===&lt;br /&gt;
&lt;br /&gt;
Wirelessly transmitting data requires three steps:&lt;br /&gt;
&lt;br /&gt;
*initialize nrf24L01+ as transmitter&lt;br /&gt;
*transmit packet&lt;br /&gt;
*wait for payload to be sent&lt;br /&gt;
&lt;br /&gt;
A basic outline for such a procedure would look like:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
char data = &amp;#039;x&amp;#039;; //data to send&lt;br /&gt;
int width = 1; //width of payload&lt;br /&gt;
&lt;br /&gt;
nrf24l01_initialize_debug(false, width, false); //initialize the 24L01 to the debug configuration as TX, 1  data byte, and auto-ack disabled&lt;br /&gt;
&lt;br /&gt;
nrf24l01_write_tx_payload(&amp;amp;data, width, true); //add char to Tx queue, and transmit immediately  (char * data, int width, bool transmit_now)&lt;br /&gt;
&lt;br /&gt;
while(!(nrf24l01_irq_pin_active() &amp;amp;&amp;amp; nrf24l01_irq_tx_ds_active())); //wait until IRQ status tells us that it is done transmitting&lt;br /&gt;
&lt;br /&gt;
nrf24l01_irq_clear_all(); //clear all interrupts in the 24L01&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A fully functional [[media:nrf-tx.c|transmitter c-file]] is available. It is intended to work with the receiving code file, available below, and allows for a variable payload.&lt;br /&gt;
&lt;br /&gt;
===Receiver Code===&lt;br /&gt;
Similarly, receiving data from a wireless link requires three steps:&lt;br /&gt;
*initialize nrf24L01+ as receiver&lt;br /&gt;
*wait for incoming packet&lt;br /&gt;
*write packet to memory&lt;br /&gt;
&lt;br /&gt;
That would look like: &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
char data; //variable to recieve incoming data&lt;br /&gt;
int width = 1; //width of payload&lt;br /&gt;
&lt;br /&gt;
nrf24l01_initialize_debug(true, width, false); //initialize the 24L01 to the debug configuration as RX, 1  data byte, and auto-ack disabled&lt;br /&gt;
&lt;br /&gt;
while(!(nrf24l01_irq_pin_active() &amp;amp;&amp;amp; nrf24l01_irq_rx_dr_active())); //wait to receive a packet&lt;br /&gt;
&lt;br /&gt;
nrf24l01_read_rx_payload(&amp;amp;data, width); //get the payload into data&lt;br /&gt;
&lt;br /&gt;
nrf24l01_irq_clear_all(); //clear interrupts&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A fully functional [[media:nrf-rx.c|receiver c-file]] is available. It is intended to work with the transmitter code file, available above, and allows for a variable payload.&lt;br /&gt;
&lt;br /&gt;
===Handling Multi-byte Payloads===&lt;br /&gt;
Transmitting and receiving payloads of widths larger than one byte are handled the same exact way as described as above, except that instead of having a a single char data variable, you would have an array of chars as your data variable. Then rather then pass in the memory of address of &amp;lt;code&amp;gt;data &amp;lt;/code&amp;gt; you can simply pass in &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt; itself,  because in C, the variable representing an array is synonymous with the memory address of its first element. Examples of this are available in the attached C files.&lt;br /&gt;
&lt;br /&gt;
===Bidirectional Communication===&lt;br /&gt;
While technically the nrf24l01+ chip can only be in one mode (transmitting/receiving) at a given instant, with some clever programming you can still get a bidirectional link established between two chips. The [[media:nrf-bidirectional.c| full code for bidirectional communication]] is available on this page. Basically, the chip sits in receiver mode, listening for any incoming packets. If it receives one, it displays it to the screen. However, there in the event that a key is pressed on the local terminal, the PIC switches the mode from receiving to transmitting, transmits the data received locally, and then goes back to receiver mode.   It is not a perfect system because if a packet reaches a chip while the chip is in the middle of transmitting a packet itself, it will not pick up the packet in the air. However, the chance of this sort of situation happening would be rare, depending on the application of the system. &lt;br /&gt;
&lt;br /&gt;
To establish a bidirectional link, both PICs should have the same bidirectional c-file loaded (but this is not necessary: e.g. one PIC could only be able to transmit, and it would still be a viable one-way link ). If the on air data rate is set to 1 Mbps, then this bidirectional c-file is compatible with the [http://www.sparkfun.com/commerce/product_info.php?products_id=9019 Nordic USB Serial Converter] (note that the Nordic USB-Serial converter is only compatible with a payload width of four bytes). The payload width of the bidirectional link can be adjusted with the &amp;quot;[&amp;quot; and &amp;quot;]&amp;quot; keys, exactly as with the above code.&lt;br /&gt;
&lt;br /&gt;
==Data Rates==&lt;br /&gt;
&lt;br /&gt;
Basic timed tests were done to find out how long it took to transmit and receive different sized payloads. These tests were done by sending a packet wirelessly, then timing how long it took to get it back. A pin was raised to high while waiting and then dropped when it was received. These periods were then measured on an oscilloscope, and then averaged. The times used were only those that had 100% return rate. However, the accuracy of these packets was not checked beyond the built in CRC error-checking within the packets themselves. The rates here are to go send out a transmission and then receive it back, so the rate should be doubled for only transmitting in one direction.&lt;br /&gt;
[[Image:bps-nrf24l01.jpg|center]]&lt;/div&gt;</summary>
		<author><name>AndrewKessler</name></author>
	</entry>
	<entry>
		<id>https://hades.mech.northwestern.edu//index.php?title=PIC32MX:_High-speed_Wireless_Communication&amp;diff=19010</id>
		<title>PIC32MX: High-speed Wireless Communication</title>
		<link rel="alternate" type="text/html" href="https://hades.mech.northwestern.edu//index.php?title=PIC32MX:_High-speed_Wireless_Communication&amp;diff=19010"/>
		<updated>2010-08-26T21:39:23Z</updated>

		<summary type="html">&lt;p&gt;AndrewKessler: /* Initialization Functions */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Overview ==&lt;br /&gt;
&lt;br /&gt;
[[Image:nrf-pic1.jpg|thumb|nrf24L01+ wireless chip with pins attatched]]&lt;br /&gt;
This wiki describes how to wire a [http://www.sparkfun.com/commerce/product_info.php?products_id=691 nRF24L01+ chip] (&amp;quot;wireless chip&amp;quot;) to a PIC32 board and includes annotated code describing the functions that facilitate the transmitting and receiving of wireless data. A  [[media:Wireless-ppt.pdf|PowerPoint presentation]] covering much of the introductory information available on this page is also available. &lt;br /&gt;
&lt;br /&gt;
To operate the system, you must properly connect the wireless chips to the PIC32s, load the transmitter code onto the PIC that you wish to act as a transmitter, load the receiver code onto the PIC that you wish to act as a receiver, properly connect an RS232 cable to the PIC and open a serial communication program (e.g. HyperTerminal or [http://chiark.greenend.org.uk/~sgtatham/putty/download.html putty]), and turn the NU32 boards on. If you use the c-files provided on this pages (and everything else is set up properly), the transmitting PIC will broadcast  any characters received from the PC via RS232, and the receiving PIC will display what it receives from wireless link on the PC via RS232. The payload width can be adjusted using the &amp;quot;[&amp;quot; and &amp;quot;]&amp;quot; keys on both the transmitting and receiving PICs. Both wireless chips must be set to the same payload width in order to communicate. Payload widths may vary from 1 to 32. The transmitting PIC will not transmit until enough characters have been entered to fill a payload. Once enough characters have been entered into the transmitting PIC, the serial display will move to a new line to signal transmission.&lt;br /&gt;
&lt;br /&gt;
==Chip Basics==&lt;br /&gt;
The nrf24L01+ Module is a breakout of the nrf24L01+ 2.4 GHz transceiver, with an on board antenna. In order to get a wireless link up and running, the following parameters must be consistent between a transmitter and receiver chip:&lt;br /&gt;
&lt;br /&gt;
===Channels===&lt;br /&gt;
The channel of the nrf24L01+ chip is the frequency that it broadcasts and receives data from. The channel can range from 2.4 GHz to 2.525 GHz, at intervals no more than 1 MHz. The exact distance between channels is dependent on the on air data rate. Two wireless chips must be tuned to the same channel in order to communicate.  See the Air Data Rate section for necessary channel spacing.&lt;br /&gt;
&lt;br /&gt;
===Air Data Rate===&lt;br /&gt;
The air data rate is the rate at which the chip transmits bits wirelessly (and the rate at which it looks for them). The nrf24L01+ chip has three selectable data rates: 250 kbps, 1 Mbps, and 2 Mbps. Faster data rates draw less current, but require a greater distance between channels. Slower data rates give you the option of more channels and better receiver sensitivity, for the obvious trade off of speed. Data rates of 250 kbps and 1 Mbps require channel spacing of at least 1 MHz (allowing for 125 unique channels), and a data rate of 2 Mbps requires spacing of 2 MHz between channels (allowing for 62 channels).  Two wireless chips will not be able to communicate if they are not set to the same on air data rate.&lt;br /&gt;
&lt;br /&gt;
===Payload Width===&lt;br /&gt;
The payload is the actual data you are trying to send over a wireless link, and the payload width is how many bytes are contained within each payload. The nfr24L01+ is capable of supporting payloads up to 32 bytes. A transmitter and receiver must be set to the same payload in order to communicate. Transmission speeds for different sizes payloads are analyzed below. &lt;br /&gt;
&lt;br /&gt;
===Addresses &amp;amp; Pipes===&lt;br /&gt;
Every wireless transmission is preceded by the address of the intended receiver. The nrf24L01+ chip has 6 different receiving pipes, which means it may act as 6 receivers with 6 different addresses. Addresses may be three, four, or five bytes long. The addresses for pipe 0 and 1 may be completely different, but the addresses for pipes 2, 3, and 4 may only differ from the address of pipe 1 by their least significant byte. All active pipes feed into the same 3-packet-deep  incoming transmission queue.  Each pipe may also be set to a expect a different payload width.&lt;br /&gt;
&lt;br /&gt;
== Circuit ==&lt;br /&gt;
&lt;br /&gt;
[[Image:Wireless-circuit.jpg|thumb|Schematic of the nRF24L01+ connected to the PIC32_NU32 board]]&lt;br /&gt;
&lt;br /&gt;
The wireless chip has 8 pins that need to be wired to the PIC (all I/O are relative to PIC):&lt;br /&gt;
&lt;br /&gt;
*Vcc: +3.3 Vdc supply&amp;lt;br&amp;gt;&lt;br /&gt;
*CE:  uC pin C1 (input)&amp;lt;br&amp;gt;&lt;br /&gt;
*CSN: uC pin C2 (output) &amp;lt;br&amp;gt;&lt;br /&gt;
*SCK: uC pin D10, configured as SCK(SPI) (output)&amp;lt;br&amp;gt;&lt;br /&gt;
*MOSI: uC pin D0, configured as SDO(SPI) (output) &amp;lt;br&amp;gt;&lt;br /&gt;
*MISO: uC pin C4, configured as SDI(SPI) (input)&amp;lt;br&amp;gt;&lt;br /&gt;
*IRQ: uC pin B0 (input) &amp;lt;br&amp;gt;&lt;br /&gt;
*GND: common digital ground&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The +3.3V and ground are provided by the NU32 board. The term &amp;quot;uC&amp;quot; above stands for microcontroller, which is the PIC32 in our case. &lt;br /&gt;
&lt;br /&gt;
Descriptions of the wireless chip&amp;#039;s pins can be found in Brennan Ball&amp;#039;s DIYembedded [http://www.diyembedded.com/tutorials/nrf24l01_0/nrf24l01_tutorial_0.pdf Tutorial 0]. The SCK, MOSI, and MISO pins interface with the SPI on the PIC32 which allows for communication between the PIC and the wireless chip. The GPIO pins will be initialized as digital inputs or outputs in the code to enable/disable the wireless chip and check the wireless data transfer/receive stats.&lt;br /&gt;
&lt;br /&gt;
In order to print information from the PIC to the PC, we need to wire an [[PIC_RS232]] cable&amp;#039;s transfer and receive lines to the UART ports of the NU32 board (F4, F5).&lt;br /&gt;
&lt;br /&gt;
==Code==&lt;br /&gt;
&lt;br /&gt;
===Driver===&lt;br /&gt;
Besides the main C files for the transmitter and receiver, the project also needs the [[media:Wireless-files.zip|nRF24L01.h header file and C file]]. These driver files were created by Brennan Ball, and are explained in detail in his [http://blog.diyembedded.com/ tutorials]. The following things must be changed in the header file available on his website to make it compatible with the NU32 board:&lt;br /&gt;
*pin registers and masks must be set to the appropriate values&lt;br /&gt;
*the &amp;quot;HardwareProfile.h&amp;quot; NU32 specific file must be included &lt;br /&gt;
&lt;br /&gt;
These changes are accounted for the the driver available on this page. All of the SPI functions trace back to a single function to send and read a single byte, which must be defined in the main c file. &lt;br /&gt;
&lt;br /&gt;
This function is available here: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 unsigned char spi_send_read_byte(unsigned char byte) {&lt;br /&gt;
  	 unsigned short	txData, rxData; // transmit, receive characters&lt;br /&gt;
   	 int chn = 1; // SPI channel to use (1 or 2)&lt;br /&gt;
  	 &lt;br /&gt;
   	 txData = byte; // take inputted byte and store into txData   &lt;br /&gt;
   	 SpiChnPutC(chn, txData);			// send data&lt;br /&gt;
 	 rxData = SpiChnGetC(chn);			// retreive over channel chn the received data into rxData&lt;br /&gt;
    &lt;br /&gt;
  	 return rxData; &lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
===Initialization Functions===&lt;br /&gt;
In order to get a wireless link up and running, you will need to initialize both the wireless chip and SPI communication on the PIC. &lt;br /&gt;
To intialize SPI on the PIC, create the following function in your main C file:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;void SpiInitDevice(int chn, int isMaster, int frmEn, int frmMaster) {&lt;br /&gt;
   	 unsigned int config = SPI_CON_MODE8|SPI_CON_SMP|SPI_CON_ON;	// SPI configuration word&lt;br /&gt;
   	 if(isMaster)&lt;br /&gt;
   	 {&lt;br /&gt;
   		 config|=SPI_CON_MSTEN;&lt;br /&gt;
   	 }&lt;br /&gt;
   	 if(frmEn)&lt;br /&gt;
   	 {&lt;br /&gt;
   		 config|=SPI_CON_FRMEN;&lt;br /&gt;
   		 if(!frmMaster) {   &lt;br /&gt;
   			 config|=SPI_CON_FRMSYNC;&lt;br /&gt;
      	 }&lt;br /&gt;
   	 }&lt;br /&gt;
  	 SpiChnOpen(chn, config, 4);	// divide fpb by 4, configure the I/O ports. Not using SS in this example&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
You can then call this function with the call &amp;lt;code&amp;gt; SpiInitDevice(1,1,0,0) &amp;lt;/code&amp;gt; to initalize SPI channel 1 on the PIC. &lt;br /&gt;
&lt;br /&gt;
To initialize the nrf24L01+ chip itself, you have to options. You can either use &amp;lt;code&amp;gt; nrf24L01_initialize(..) &amp;lt;/code&amp;gt; which gives  you the opportunity to manually define every register in the chip right from the start. However, this function has 21 arguments, so it is not the most convenient to use if you don&amp;#039;t have to. Instead, you can use &amp;lt;code&amp;gt; nrf24L01_initialize_debug(bool rx, int width, bool auto_ack_on) &amp;lt;/code&amp;gt;, which gives you the option to specify whether or not the chip is a receiver or transmitter, what the payload width is, and whether or not to enable auto-acknowledge. However, it limits you to Pipe 0, an air data rate of 2 Mpbs, and RF Channel 2. However, these limitations can be adjusted easily after initialization using additional functions (see the library for all available functions). So, for example, to initialize your chip as a transmitter with a payload width of one byte and no auto-acknowledgement, you could call &amp;lt;code&amp;gt; nrf24L01_initialize_debug(0,1,0)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If you wish to display information to the screen or receive information from the keyboard, you will have to initialize the RS232 connection as well. This can be done with the following code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
int pbClk = SYSTEMConfigPerformance(SYS_FREQ);&lt;br /&gt;
initUART2(pbClk);&lt;br /&gt;
&lt;br /&gt;
 void initUART2(int pbClk) {&lt;br /&gt;
  	 #define config1 	UART_EN | UART_IDLE_CON | UART_RX_TX | UART_DIS_WAKE | UART_DIS_LOOPBACK | UART_DIS_ABAUD | UART_NO_PAR_8BIT | UART_1STOPBIT | UART_IRDA_DIS | UART_DIS_BCLK_CTS_RTS| UART_NORMAL_RX | UART_BRGH_SIXTEEN&lt;br /&gt;
  	 #define config2		UART_TX_PIN_LOW | UART_RX_ENABLE | UART_TX_ENABLE | UART_INT_TX | UART_INT_RX_CHAR | UART_ADR_DETECT_DIS | UART_RX_OVERRUN_CLEAR	&lt;br /&gt;
   	 OpenUART2( config1, config2, pbClk/16/DESIRED_BAUDRATE-1);	// calculate actual BAUD generate value.&lt;br /&gt;
   	 ConfigIntUART2(UART_INT_PR2 | UART_RX_INT_EN);&lt;br /&gt;
   	 //INTEnableSystemMultiVectoredInt(); //interrupts enabled?&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Transmitter Code===&lt;br /&gt;
&lt;br /&gt;
Wirelessly transmitting data requires three steps:&lt;br /&gt;
&lt;br /&gt;
*initialize nrf24L01+ as transmitter&lt;br /&gt;
*transmit packet&lt;br /&gt;
*wait for payload to be sent&lt;br /&gt;
&lt;br /&gt;
A basic outline for such a procedure would look like:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
char data = &amp;#039;x&amp;#039;; //data to send&lt;br /&gt;
int width = 1; //width of payload&lt;br /&gt;
&lt;br /&gt;
nrf24l01_initialize_debug(false, width, false); //initialize the 24L01 to the debug configuration as TX, 1  data byte, and auto-ack disabled&lt;br /&gt;
&lt;br /&gt;
nrf24l01_write_tx_payload(&amp;amp;data, width, true); //add char to Tx queue, and transmit immediately  (char * data, int width, bool transmit_now)&lt;br /&gt;
&lt;br /&gt;
while(!(nrf24l01_irq_pin_active() &amp;amp;&amp;amp; nrf24l01_irq_tx_ds_active())); //wait until IRQ status tells us that it is done transmitting&lt;br /&gt;
&lt;br /&gt;
nrf24l01_irq_clear_all(); //clear all interrupts in the 24L01&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A fully functional [[media:nrf-tx.c|transmitter c-file]] is available. It is intended to work with the receiving code file, available below, and allows for a variable payload.&lt;br /&gt;
&lt;br /&gt;
===Receiver Code===&lt;br /&gt;
Similarly, receiving data from a wireless link requires three steps:&lt;br /&gt;
*initialize nrf24L01+ as receiver&lt;br /&gt;
*wait for incoming packet&lt;br /&gt;
*write packet to memory&lt;br /&gt;
&lt;br /&gt;
That would look like: &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
char data; //variable to recieve incoming data&lt;br /&gt;
int width = 1; //width of payload&lt;br /&gt;
&lt;br /&gt;
nrf24l01_initialize_debug(true, width, false); //initialize the 24L01 to the debug configuration as RX, 1  data byte, and auto-ack disabled&lt;br /&gt;
&lt;br /&gt;
while(!(nrf24l01_irq_pin_active() &amp;amp;&amp;amp; nrf24l01_irq_rx_dr_active())); //wait to receive a packet&lt;br /&gt;
&lt;br /&gt;
nrf24l01_read_rx_payload(&amp;amp;data, width); //get the payload into data&lt;br /&gt;
&lt;br /&gt;
nrf24l01_irq_clear_all(); //clear interrupts&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A fully functional [[media:nrf-rx.c|receiver c-file]] is available. It is intended to work with the transmitter code file, available above, and allows for a variable payload.&lt;br /&gt;
&lt;br /&gt;
===Handling Multi-byte Payloads===&lt;br /&gt;
Transmitting and receiving payloads of widths larger than one byte are handled the same exact way as described as above, except that instead of having a a single char data variable, you would have an array of chars as your data variable. Then rather then pass in the memory of address of &amp;lt;code&amp;gt;data &amp;lt;/code&amp;gt; you can simply pass in &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt; itself,  because in C, the variable representing an array is synonymous with the memory address of its first element. Examples of this are available in the attached C files.&lt;br /&gt;
&lt;br /&gt;
===Bidirectional Communication===&lt;br /&gt;
While technically the nrf24l01+ chip can only be in one mode (transmitting/receiving) at a given instant, with some clever programming you can still get a bidirectional link established between two chips. The [[media:nrf-bidirectional.c| full code for bidirectional communication]] is available on this page. Basically, the chip sits in receiver mode, listening for any incoming packets. If it receives one, it displays it to the screen. However, there in the event that a key is pressed on the local terminal, the PIC switches the mode from receiving to transmitting, transmits the data received locally, and then goes back to receiver mode.   It is not a perfect system because if a packet reaches a chip while the chip is in the middle of transmitting a packet itself, it will not pick up the packet in the air. However, the chance of this sort of situation happening would be rare, depending on the application of the system. &lt;br /&gt;
&lt;br /&gt;
To establish a bidirectional link, both PICs should have the same bidirectional c-file loaded (but this is not necessary: e.g. one PIC could only be able to transmit, and it would still be a viable one-way link ). If the on air data rate is set to 1 Mbps, then this bidirectional c-file is compatible with the [http://www.sparkfun.com/commerce/product_info.php?products_id=9019 Nordic USB Serial Converter] (note that the Nordic USB-Serial converter is only compatible with a payload width of four bytes). The payload width of the bidirectional link can be adjusted with the &amp;quot;[&amp;quot; and &amp;quot;]&amp;quot; keys, exactly as with the above code.&lt;br /&gt;
&lt;br /&gt;
==Data Rates==&lt;br /&gt;
&lt;br /&gt;
Basic timed tests were done to find out how long it took to transmit and receive different sized payloads. These tests were done by sending a packet wirelessly, then timing how long it took to get it back. A pin was raised to high while waiting and then dropped when it was received. These periods were then measured on an oscilloscope, and then averaged. The times used were only those that had 100% return rate. However, the accuracy of these packets was not checked beyond the built in CRC error-checking within the packets themselves. The rates here are to go send out a transmission and then receive it back, so the rate should be doubled for only transmitting in one direction.&lt;br /&gt;
[[Image:bps-nrf24l01.jpg|center]]&lt;/div&gt;</summary>
		<author><name>AndrewKessler</name></author>
	</entry>
	<entry>
		<id>https://hades.mech.northwestern.edu//index.php?title=PIC32MX:_High-speed_Wireless_Communication&amp;diff=19009</id>
		<title>PIC32MX: High-speed Wireless Communication</title>
		<link rel="alternate" type="text/html" href="https://hades.mech.northwestern.edu//index.php?title=PIC32MX:_High-speed_Wireless_Communication&amp;diff=19009"/>
		<updated>2010-08-26T21:38:52Z</updated>

		<summary type="html">&lt;p&gt;AndrewKessler: /* Initialization Functions */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Overview ==&lt;br /&gt;
&lt;br /&gt;
[[Image:nrf-pic1.jpg|thumb|nrf24L01+ wireless chip with pins attatched]]&lt;br /&gt;
This wiki describes how to wire a [http://www.sparkfun.com/commerce/product_info.php?products_id=691 nRF24L01+ chip] (&amp;quot;wireless chip&amp;quot;) to a PIC32 board and includes annotated code describing the functions that facilitate the transmitting and receiving of wireless data. A  [[media:Wireless-ppt.pdf|PowerPoint presentation]] covering much of the introductory information available on this page is also available. &lt;br /&gt;
&lt;br /&gt;
To operate the system, you must properly connect the wireless chips to the PIC32s, load the transmitter code onto the PIC that you wish to act as a transmitter, load the receiver code onto the PIC that you wish to act as a receiver, properly connect an RS232 cable to the PIC and open a serial communication program (e.g. HyperTerminal or [http://chiark.greenend.org.uk/~sgtatham/putty/download.html putty]), and turn the NU32 boards on. If you use the c-files provided on this pages (and everything else is set up properly), the transmitting PIC will broadcast  any characters received from the PC via RS232, and the receiving PIC will display what it receives from wireless link on the PC via RS232. The payload width can be adjusted using the &amp;quot;[&amp;quot; and &amp;quot;]&amp;quot; keys on both the transmitting and receiving PICs. Both wireless chips must be set to the same payload width in order to communicate. Payload widths may vary from 1 to 32. The transmitting PIC will not transmit until enough characters have been entered to fill a payload. Once enough characters have been entered into the transmitting PIC, the serial display will move to a new line to signal transmission.&lt;br /&gt;
&lt;br /&gt;
==Chip Basics==&lt;br /&gt;
The nrf24L01+ Module is a breakout of the nrf24L01+ 2.4 GHz transceiver, with an on board antenna. In order to get a wireless link up and running, the following parameters must be consistent between a transmitter and receiver chip:&lt;br /&gt;
&lt;br /&gt;
===Channels===&lt;br /&gt;
The channel of the nrf24L01+ chip is the frequency that it broadcasts and receives data from. The channel can range from 2.4 GHz to 2.525 GHz, at intervals no more than 1 MHz. The exact distance between channels is dependent on the on air data rate. Two wireless chips must be tuned to the same channel in order to communicate.  See the Air Data Rate section for necessary channel spacing.&lt;br /&gt;
&lt;br /&gt;
===Air Data Rate===&lt;br /&gt;
The air data rate is the rate at which the chip transmits bits wirelessly (and the rate at which it looks for them). The nrf24L01+ chip has three selectable data rates: 250 kbps, 1 Mbps, and 2 Mbps. Faster data rates draw less current, but require a greater distance between channels. Slower data rates give you the option of more channels and better receiver sensitivity, for the obvious trade off of speed. Data rates of 250 kbps and 1 Mbps require channel spacing of at least 1 MHz (allowing for 125 unique channels), and a data rate of 2 Mbps requires spacing of 2 MHz between channels (allowing for 62 channels).  Two wireless chips will not be able to communicate if they are not set to the same on air data rate.&lt;br /&gt;
&lt;br /&gt;
===Payload Width===&lt;br /&gt;
The payload is the actual data you are trying to send over a wireless link, and the payload width is how many bytes are contained within each payload. The nfr24L01+ is capable of supporting payloads up to 32 bytes. A transmitter and receiver must be set to the same payload in order to communicate. Transmission speeds for different sizes payloads are analyzed below. &lt;br /&gt;
&lt;br /&gt;
===Addresses &amp;amp; Pipes===&lt;br /&gt;
Every wireless transmission is preceded by the address of the intended receiver. The nrf24L01+ chip has 6 different receiving pipes, which means it may act as 6 receivers with 6 different addresses. Addresses may be three, four, or five bytes long. The addresses for pipe 0 and 1 may be completely different, but the addresses for pipes 2, 3, and 4 may only differ from the address of pipe 1 by their least significant byte. All active pipes feed into the same 3-packet-deep  incoming transmission queue.  Each pipe may also be set to a expect a different payload width.&lt;br /&gt;
&lt;br /&gt;
== Circuit ==&lt;br /&gt;
&lt;br /&gt;
[[Image:Wireless-circuit.jpg|thumb|Schematic of the nRF24L01+ connected to the PIC32_NU32 board]]&lt;br /&gt;
&lt;br /&gt;
The wireless chip has 8 pins that need to be wired to the PIC (all I/O are relative to PIC):&lt;br /&gt;
&lt;br /&gt;
*Vcc: +3.3 Vdc supply&amp;lt;br&amp;gt;&lt;br /&gt;
*CE:  uC pin C1 (input)&amp;lt;br&amp;gt;&lt;br /&gt;
*CSN: uC pin C2 (output) &amp;lt;br&amp;gt;&lt;br /&gt;
*SCK: uC pin D10, configured as SCK(SPI) (output)&amp;lt;br&amp;gt;&lt;br /&gt;
*MOSI: uC pin D0, configured as SDO(SPI) (output) &amp;lt;br&amp;gt;&lt;br /&gt;
*MISO: uC pin C4, configured as SDI(SPI) (input)&amp;lt;br&amp;gt;&lt;br /&gt;
*IRQ: uC pin B0 (input) &amp;lt;br&amp;gt;&lt;br /&gt;
*GND: common digital ground&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The +3.3V and ground are provided by the NU32 board. The term &amp;quot;uC&amp;quot; above stands for microcontroller, which is the PIC32 in our case. &lt;br /&gt;
&lt;br /&gt;
Descriptions of the wireless chip&amp;#039;s pins can be found in Brennan Ball&amp;#039;s DIYembedded [http://www.diyembedded.com/tutorials/nrf24l01_0/nrf24l01_tutorial_0.pdf Tutorial 0]. The SCK, MOSI, and MISO pins interface with the SPI on the PIC32 which allows for communication between the PIC and the wireless chip. The GPIO pins will be initialized as digital inputs or outputs in the code to enable/disable the wireless chip and check the wireless data transfer/receive stats.&lt;br /&gt;
&lt;br /&gt;
In order to print information from the PIC to the PC, we need to wire an [[PIC_RS232]] cable&amp;#039;s transfer and receive lines to the UART ports of the NU32 board (F4, F5).&lt;br /&gt;
&lt;br /&gt;
==Code==&lt;br /&gt;
&lt;br /&gt;
===Driver===&lt;br /&gt;
Besides the main C files for the transmitter and receiver, the project also needs the [[media:Wireless-files.zip|nRF24L01.h header file and C file]]. These driver files were created by Brennan Ball, and are explained in detail in his [http://blog.diyembedded.com/ tutorials]. The following things must be changed in the header file available on his website to make it compatible with the NU32 board:&lt;br /&gt;
*pin registers and masks must be set to the appropriate values&lt;br /&gt;
*the &amp;quot;HardwareProfile.h&amp;quot; NU32 specific file must be included &lt;br /&gt;
&lt;br /&gt;
These changes are accounted for the the driver available on this page. All of the SPI functions trace back to a single function to send and read a single byte, which must be defined in the main c file. &lt;br /&gt;
&lt;br /&gt;
This function is available here: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 unsigned char spi_send_read_byte(unsigned char byte) {&lt;br /&gt;
  	 unsigned short	txData, rxData; // transmit, receive characters&lt;br /&gt;
   	 int chn = 1; // SPI channel to use (1 or 2)&lt;br /&gt;
  	 &lt;br /&gt;
   	 txData = byte; // take inputted byte and store into txData   &lt;br /&gt;
   	 SpiChnPutC(chn, txData);			// send data&lt;br /&gt;
 	 rxData = SpiChnGetC(chn);			// retreive over channel chn the received data into rxData&lt;br /&gt;
    &lt;br /&gt;
  	 return rxData; &lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
===Initialization Functions===&lt;br /&gt;
In order to get a wireless link up and running, you will need to initialize both the wireless chip and SPI communication on the PIC. &lt;br /&gt;
To intialize SPI on the PIC, create the following function in your main C file:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;void SpiInitDevice(int chn, int isMaster, int frmEn, int frmMaster) {&lt;br /&gt;
   	 unsigned int config = SPI_CON_MODE8|SPI_CON_SMP|SPI_CON_ON;	// SPI configuration word&lt;br /&gt;
   	 if(isMaster)&lt;br /&gt;
   	 {&lt;br /&gt;
   		 config|=SPI_CON_MSTEN;&lt;br /&gt;
   	 }&lt;br /&gt;
   	 if(frmEn)&lt;br /&gt;
   	 {&lt;br /&gt;
   		 config|=SPI_CON_FRMEN;&lt;br /&gt;
   		 if(!frmMaster) {   &lt;br /&gt;
   			 config|=SPI_CON_FRMSYNC;&lt;br /&gt;
      	 }&lt;br /&gt;
   	 }&lt;br /&gt;
  	 SpiChnOpen(chn, config, 4);	// divide fpb by 4, configure the I/O ports. Not using SS in this example&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
You can then call this function with the call &amp;lt;code&amp;gt; SpiInitDevice(1,1,0,0) &amp;lt;/code&amp;gt; to initalize SPI channel 1 on the PIC. &lt;br /&gt;
&lt;br /&gt;
To initialize the nrf24L01+ chip itself, you have to options. You can either use &amp;lt;code&amp;gt; nrf24L01_initialize(..) &amp;lt;/code&amp;gt; which gives  you the opportunity to manually define every register in the chip right from the start. However, this function has 21 arguments, so it is not the most convenient to use if you don&amp;#039;t have to. Instead, you can use &amp;lt;code&amp;gt; nrf24L01_initialize_debug(bool rx, int width, bool auto_ack_on) &amp;lt;/code&amp;gt;, which gives you the option to specify whether or not the chip is a receiver or transmitter, what the payload width is, and whether or not to enable auto-acknowledge. However, it limits you to Pipe 0, an air data rate of 2 Mpbs, and RF Channel 2. However, these limitations can be adjusted easily after initialization using additional functions (see the library for all available functions). So, for example, to initialize your chip as a transmitter with a payload width of one byte and no auto-acknowledgement, you could call &amp;lt;code&amp;gt; nrf24L01_initialize_debug(0,1,0)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If you wish to display information to the screen or receive information from the keyboard, you will have to initialize the RS232 connection as well. This can be done with the following code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
int pbClk = SYSTEMConfigPerformance(SYS_FREQ);&lt;br /&gt;
initUART2(pbClk);&lt;br /&gt;
&lt;br /&gt;
 void initUART2(int pbClk) {&lt;br /&gt;
  	 #define config1 	UART_EN | UART_IDLE_CON | UART_RX_TX | UART_DIS_WAKE | UART_DIS_LOOPBACK | UART_DIS_ABAUD | UART_NO_PAR_8BIT | UART_1STOPBIT | UART_IRDA_DIS | UART_DIS_BCLK_CTS_RTS| UART_NORMAL_RX | UART_BRGH_SIXTEEN&lt;br /&gt;
  	 #define config2		UART_TX_PIN_LOW | UART_RX_ENABLE | UART_TX_ENABLE | UART_INT_TX | UART_INT_RX_CHAR | UART_ADR_DETECT_DIS | UART_RX_OVERRUN_CLEAR	&lt;br /&gt;
   	 OpenUART2( config1, config2, pbClk/16/DESIRED_BAUDRATE-1);	// calculate actual BAUD generate value.&lt;br /&gt;
   	 ConfigIntUART2(UART_INT_PR2 | UART_RX_INT_EN);&lt;br /&gt;
   	 //INTEnableSystemMultiVectoredInt();&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Transmitter Code===&lt;br /&gt;
&lt;br /&gt;
Wirelessly transmitting data requires three steps:&lt;br /&gt;
&lt;br /&gt;
*initialize nrf24L01+ as transmitter&lt;br /&gt;
*transmit packet&lt;br /&gt;
*wait for payload to be sent&lt;br /&gt;
&lt;br /&gt;
A basic outline for such a procedure would look like:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
char data = &amp;#039;x&amp;#039;; //data to send&lt;br /&gt;
int width = 1; //width of payload&lt;br /&gt;
&lt;br /&gt;
nrf24l01_initialize_debug(false, width, false); //initialize the 24L01 to the debug configuration as TX, 1  data byte, and auto-ack disabled&lt;br /&gt;
&lt;br /&gt;
nrf24l01_write_tx_payload(&amp;amp;data, width, true); //add char to Tx queue, and transmit immediately  (char * data, int width, bool transmit_now)&lt;br /&gt;
&lt;br /&gt;
while(!(nrf24l01_irq_pin_active() &amp;amp;&amp;amp; nrf24l01_irq_tx_ds_active())); //wait until IRQ status tells us that it is done transmitting&lt;br /&gt;
&lt;br /&gt;
nrf24l01_irq_clear_all(); //clear all interrupts in the 24L01&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A fully functional [[media:nrf-tx.c|transmitter c-file]] is available. It is intended to work with the receiving code file, available below, and allows for a variable payload.&lt;br /&gt;
&lt;br /&gt;
===Receiver Code===&lt;br /&gt;
Similarly, receiving data from a wireless link requires three steps:&lt;br /&gt;
*initialize nrf24L01+ as receiver&lt;br /&gt;
*wait for incoming packet&lt;br /&gt;
*write packet to memory&lt;br /&gt;
&lt;br /&gt;
That would look like: &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
char data; //variable to recieve incoming data&lt;br /&gt;
int width = 1; //width of payload&lt;br /&gt;
&lt;br /&gt;
nrf24l01_initialize_debug(true, width, false); //initialize the 24L01 to the debug configuration as RX, 1  data byte, and auto-ack disabled&lt;br /&gt;
&lt;br /&gt;
while(!(nrf24l01_irq_pin_active() &amp;amp;&amp;amp; nrf24l01_irq_rx_dr_active())); //wait to receive a packet&lt;br /&gt;
&lt;br /&gt;
nrf24l01_read_rx_payload(&amp;amp;data, width); //get the payload into data&lt;br /&gt;
&lt;br /&gt;
nrf24l01_irq_clear_all(); //clear interrupts&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A fully functional [[media:nrf-rx.c|receiver c-file]] is available. It is intended to work with the transmitter code file, available above, and allows for a variable payload.&lt;br /&gt;
&lt;br /&gt;
===Handling Multi-byte Payloads===&lt;br /&gt;
Transmitting and receiving payloads of widths larger than one byte are handled the same exact way as described as above, except that instead of having a a single char data variable, you would have an array of chars as your data variable. Then rather then pass in the memory of address of &amp;lt;code&amp;gt;data &amp;lt;/code&amp;gt; you can simply pass in &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt; itself,  because in C, the variable representing an array is synonymous with the memory address of its first element. Examples of this are available in the attached C files.&lt;br /&gt;
&lt;br /&gt;
===Bidirectional Communication===&lt;br /&gt;
While technically the nrf24l01+ chip can only be in one mode (transmitting/receiving) at a given instant, with some clever programming you can still get a bidirectional link established between two chips. The [[media:nrf-bidirectional.c| full code for bidirectional communication]] is available on this page. Basically, the chip sits in receiver mode, listening for any incoming packets. If it receives one, it displays it to the screen. However, there in the event that a key is pressed on the local terminal, the PIC switches the mode from receiving to transmitting, transmits the data received locally, and then goes back to receiver mode.   It is not a perfect system because if a packet reaches a chip while the chip is in the middle of transmitting a packet itself, it will not pick up the packet in the air. However, the chance of this sort of situation happening would be rare, depending on the application of the system. &lt;br /&gt;
&lt;br /&gt;
To establish a bidirectional link, both PICs should have the same bidirectional c-file loaded (but this is not necessary: e.g. one PIC could only be able to transmit, and it would still be a viable one-way link ). If the on air data rate is set to 1 Mbps, then this bidirectional c-file is compatible with the [http://www.sparkfun.com/commerce/product_info.php?products_id=9019 Nordic USB Serial Converter] (note that the Nordic USB-Serial converter is only compatible with a payload width of four bytes). The payload width of the bidirectional link can be adjusted with the &amp;quot;[&amp;quot; and &amp;quot;]&amp;quot; keys, exactly as with the above code.&lt;br /&gt;
&lt;br /&gt;
==Data Rates==&lt;br /&gt;
&lt;br /&gt;
Basic timed tests were done to find out how long it took to transmit and receive different sized payloads. These tests were done by sending a packet wirelessly, then timing how long it took to get it back. A pin was raised to high while waiting and then dropped when it was received. These periods were then measured on an oscilloscope, and then averaged. The times used were only those that had 100% return rate. However, the accuracy of these packets was not checked beyond the built in CRC error-checking within the packets themselves. The rates here are to go send out a transmission and then receive it back, so the rate should be doubled for only transmitting in one direction.&lt;br /&gt;
[[Image:bps-nrf24l01.jpg|center]]&lt;/div&gt;</summary>
		<author><name>AndrewKessler</name></author>
	</entry>
	<entry>
		<id>https://hades.mech.northwestern.edu//index.php?title=PIC32MX:_High-speed_Wireless_Communication&amp;diff=19008</id>
		<title>PIC32MX: High-speed Wireless Communication</title>
		<link rel="alternate" type="text/html" href="https://hades.mech.northwestern.edu//index.php?title=PIC32MX:_High-speed_Wireless_Communication&amp;diff=19008"/>
		<updated>2010-08-26T21:38:33Z</updated>

		<summary type="html">&lt;p&gt;AndrewKessler: /* Receiver Code */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Overview ==&lt;br /&gt;
&lt;br /&gt;
[[Image:nrf-pic1.jpg|thumb|nrf24L01+ wireless chip with pins attatched]]&lt;br /&gt;
This wiki describes how to wire a [http://www.sparkfun.com/commerce/product_info.php?products_id=691 nRF24L01+ chip] (&amp;quot;wireless chip&amp;quot;) to a PIC32 board and includes annotated code describing the functions that facilitate the transmitting and receiving of wireless data. A  [[media:Wireless-ppt.pdf|PowerPoint presentation]] covering much of the introductory information available on this page is also available. &lt;br /&gt;
&lt;br /&gt;
To operate the system, you must properly connect the wireless chips to the PIC32s, load the transmitter code onto the PIC that you wish to act as a transmitter, load the receiver code onto the PIC that you wish to act as a receiver, properly connect an RS232 cable to the PIC and open a serial communication program (e.g. HyperTerminal or [http://chiark.greenend.org.uk/~sgtatham/putty/download.html putty]), and turn the NU32 boards on. If you use the c-files provided on this pages (and everything else is set up properly), the transmitting PIC will broadcast  any characters received from the PC via RS232, and the receiving PIC will display what it receives from wireless link on the PC via RS232. The payload width can be adjusted using the &amp;quot;[&amp;quot; and &amp;quot;]&amp;quot; keys on both the transmitting and receiving PICs. Both wireless chips must be set to the same payload width in order to communicate. Payload widths may vary from 1 to 32. The transmitting PIC will not transmit until enough characters have been entered to fill a payload. Once enough characters have been entered into the transmitting PIC, the serial display will move to a new line to signal transmission.&lt;br /&gt;
&lt;br /&gt;
==Chip Basics==&lt;br /&gt;
The nrf24L01+ Module is a breakout of the nrf24L01+ 2.4 GHz transceiver, with an on board antenna. In order to get a wireless link up and running, the following parameters must be consistent between a transmitter and receiver chip:&lt;br /&gt;
&lt;br /&gt;
===Channels===&lt;br /&gt;
The channel of the nrf24L01+ chip is the frequency that it broadcasts and receives data from. The channel can range from 2.4 GHz to 2.525 GHz, at intervals no more than 1 MHz. The exact distance between channels is dependent on the on air data rate. Two wireless chips must be tuned to the same channel in order to communicate.  See the Air Data Rate section for necessary channel spacing.&lt;br /&gt;
&lt;br /&gt;
===Air Data Rate===&lt;br /&gt;
The air data rate is the rate at which the chip transmits bits wirelessly (and the rate at which it looks for them). The nrf24L01+ chip has three selectable data rates: 250 kbps, 1 Mbps, and 2 Mbps. Faster data rates draw less current, but require a greater distance between channels. Slower data rates give you the option of more channels and better receiver sensitivity, for the obvious trade off of speed. Data rates of 250 kbps and 1 Mbps require channel spacing of at least 1 MHz (allowing for 125 unique channels), and a data rate of 2 Mbps requires spacing of 2 MHz between channels (allowing for 62 channels).  Two wireless chips will not be able to communicate if they are not set to the same on air data rate.&lt;br /&gt;
&lt;br /&gt;
===Payload Width===&lt;br /&gt;
The payload is the actual data you are trying to send over a wireless link, and the payload width is how many bytes are contained within each payload. The nfr24L01+ is capable of supporting payloads up to 32 bytes. A transmitter and receiver must be set to the same payload in order to communicate. Transmission speeds for different sizes payloads are analyzed below. &lt;br /&gt;
&lt;br /&gt;
===Addresses &amp;amp; Pipes===&lt;br /&gt;
Every wireless transmission is preceded by the address of the intended receiver. The nrf24L01+ chip has 6 different receiving pipes, which means it may act as 6 receivers with 6 different addresses. Addresses may be three, four, or five bytes long. The addresses for pipe 0 and 1 may be completely different, but the addresses for pipes 2, 3, and 4 may only differ from the address of pipe 1 by their least significant byte. All active pipes feed into the same 3-packet-deep  incoming transmission queue.  Each pipe may also be set to a expect a different payload width.&lt;br /&gt;
&lt;br /&gt;
== Circuit ==&lt;br /&gt;
&lt;br /&gt;
[[Image:Wireless-circuit.jpg|thumb|Schematic of the nRF24L01+ connected to the PIC32_NU32 board]]&lt;br /&gt;
&lt;br /&gt;
The wireless chip has 8 pins that need to be wired to the PIC (all I/O are relative to PIC):&lt;br /&gt;
&lt;br /&gt;
*Vcc: +3.3 Vdc supply&amp;lt;br&amp;gt;&lt;br /&gt;
*CE:  uC pin C1 (input)&amp;lt;br&amp;gt;&lt;br /&gt;
*CSN: uC pin C2 (output) &amp;lt;br&amp;gt;&lt;br /&gt;
*SCK: uC pin D10, configured as SCK(SPI) (output)&amp;lt;br&amp;gt;&lt;br /&gt;
*MOSI: uC pin D0, configured as SDO(SPI) (output) &amp;lt;br&amp;gt;&lt;br /&gt;
*MISO: uC pin C4, configured as SDI(SPI) (input)&amp;lt;br&amp;gt;&lt;br /&gt;
*IRQ: uC pin B0 (input) &amp;lt;br&amp;gt;&lt;br /&gt;
*GND: common digital ground&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The +3.3V and ground are provided by the NU32 board. The term &amp;quot;uC&amp;quot; above stands for microcontroller, which is the PIC32 in our case. &lt;br /&gt;
&lt;br /&gt;
Descriptions of the wireless chip&amp;#039;s pins can be found in Brennan Ball&amp;#039;s DIYembedded [http://www.diyembedded.com/tutorials/nrf24l01_0/nrf24l01_tutorial_0.pdf Tutorial 0]. The SCK, MOSI, and MISO pins interface with the SPI on the PIC32 which allows for communication between the PIC and the wireless chip. The GPIO pins will be initialized as digital inputs or outputs in the code to enable/disable the wireless chip and check the wireless data transfer/receive stats.&lt;br /&gt;
&lt;br /&gt;
In order to print information from the PIC to the PC, we need to wire an [[PIC_RS232]] cable&amp;#039;s transfer and receive lines to the UART ports of the NU32 board (F4, F5).&lt;br /&gt;
&lt;br /&gt;
==Code==&lt;br /&gt;
&lt;br /&gt;
===Driver===&lt;br /&gt;
Besides the main C files for the transmitter and receiver, the project also needs the [[media:Wireless-files.zip|nRF24L01.h header file and C file]]. These driver files were created by Brennan Ball, and are explained in detail in his [http://blog.diyembedded.com/ tutorials]. The following things must be changed in the header file available on his website to make it compatible with the NU32 board:&lt;br /&gt;
*pin registers and masks must be set to the appropriate values&lt;br /&gt;
*the &amp;quot;HardwareProfile.h&amp;quot; NU32 specific file must be included &lt;br /&gt;
&lt;br /&gt;
These changes are accounted for the the driver available on this page. All of the SPI functions trace back to a single function to send and read a single byte, which must be defined in the main c file. &lt;br /&gt;
&lt;br /&gt;
This function is available here: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 unsigned char spi_send_read_byte(unsigned char byte) {&lt;br /&gt;
  	 unsigned short	txData, rxData; // transmit, receive characters&lt;br /&gt;
   	 int chn = 1; // SPI channel to use (1 or 2)&lt;br /&gt;
  	 &lt;br /&gt;
   	 txData = byte; // take inputted byte and store into txData   &lt;br /&gt;
   	 SpiChnPutC(chn, txData);			// send data&lt;br /&gt;
 	 rxData = SpiChnGetC(chn);			// retreive over channel chn the received data into rxData&lt;br /&gt;
    &lt;br /&gt;
  	 return rxData; &lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
===Initialization Functions===&lt;br /&gt;
In order to get a wireless link up and running, you will need to initialize both the wireless chip and SPI communication on the PIC. &lt;br /&gt;
To intialize SPI on the PIC, create the following function in your main C file:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;oid SpiInitDevice(int chn, int isMaster, int frmEn, int frmMaster) {&lt;br /&gt;
   	 unsigned int config = SPI_CON_MODE8|SPI_CON_SMP|SPI_CON_ON;	// SPI configuration word&lt;br /&gt;
   	 if(isMaster)&lt;br /&gt;
   	 {&lt;br /&gt;
   		 config|=SPI_CON_MSTEN;&lt;br /&gt;
   	 }&lt;br /&gt;
   	 if(frmEn)&lt;br /&gt;
   	 {&lt;br /&gt;
   		 config|=SPI_CON_FRMEN;&lt;br /&gt;
   		 if(!frmMaster) {   &lt;br /&gt;
   			 config|=SPI_CON_FRMSYNC;&lt;br /&gt;
      	 }&lt;br /&gt;
   	 }&lt;br /&gt;
  	 SpiChnOpen(chn, config, 4);	// divide fpb by 4, configure the I/O ports. Not using SS in this example&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
You can then call this function with the call &amp;lt;code&amp;gt; SpiInitDevice(1,1,0,0) &amp;lt;/code&amp;gt; to initalize SPI channel 1 on the PIC. &lt;br /&gt;
&lt;br /&gt;
To initialize the nrf24L01+ chip itself, you have to options. You can either use &amp;lt;code&amp;gt; nrf24L01_initialize(..) &amp;lt;/code&amp;gt; which gives  you the opportunity to manually define every register in the chip right from the start. However, this function has 21 arguments, so it is not the most convenient to use if you don&amp;#039;t have to. Instead, you can use &amp;lt;code&amp;gt; nrf24L01_initialize_debug(bool rx, int width, bool auto_ack_on) &amp;lt;/code&amp;gt;, which gives you the option to specify whether or not the chip is a receiver or transmitter, what the payload width is, and whether or not to enable auto-acknowledge. However, it limits you to Pipe 0, an air data rate of 2 Mpbs, and RF Channel 2. However, these limitations can be adjusted easily after initialization using additional functions (see the library for all available functions). So, for example, to initialize your chip as a transmitter with a payload width of one byte and no auto-acknowledgement, you could call &amp;lt;code&amp;gt; nrf24L01_initialize_debug(0,1,0)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If you wish to display information to the screen or receive information from the keyboard, you will have to initialize the RS232 connection as well. This can be done with the following code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
int	pbClk = SYSTEMConfigPerformance(SYS_FREQ);&lt;br /&gt;
initUART2(pbClk);&lt;br /&gt;
&lt;br /&gt;
 void initUART2(int pbClk) {&lt;br /&gt;
  	 #define config1 	UART_EN | UART_IDLE_CON | UART_RX_TX | UART_DIS_WAKE | UART_DIS_LOOPBACK | UART_DIS_ABAUD | UART_NO_PAR_8BIT | UART_1STOPBIT | UART_IRDA_DIS | UART_DIS_BCLK_CTS_RTS| UART_NORMAL_RX | UART_BRGH_SIXTEEN&lt;br /&gt;
  	 #define config2		UART_TX_PIN_LOW | UART_RX_ENABLE | UART_TX_ENABLE | UART_INT_TX | UART_INT_RX_CHAR | UART_ADR_DETECT_DIS | UART_RX_OVERRUN_CLEAR	&lt;br /&gt;
   	 OpenUART2( config1, config2, pbClk/16/DESIRED_BAUDRATE-1);	// calculate actual BAUD generate value.&lt;br /&gt;
   	 ConfigIntUART2(UART_INT_PR2 | UART_RX_INT_EN);&lt;br /&gt;
   	 //INTEnableSystemMultiVectoredInt();&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Transmitter Code===&lt;br /&gt;
&lt;br /&gt;
Wirelessly transmitting data requires three steps:&lt;br /&gt;
&lt;br /&gt;
*initialize nrf24L01+ as transmitter&lt;br /&gt;
*transmit packet&lt;br /&gt;
*wait for payload to be sent&lt;br /&gt;
&lt;br /&gt;
A basic outline for such a procedure would look like:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
char data = &amp;#039;x&amp;#039;; //data to send&lt;br /&gt;
int width = 1; //width of payload&lt;br /&gt;
&lt;br /&gt;
nrf24l01_initialize_debug(false, width, false); //initialize the 24L01 to the debug configuration as TX, 1  data byte, and auto-ack disabled&lt;br /&gt;
&lt;br /&gt;
nrf24l01_write_tx_payload(&amp;amp;data, width, true); //add char to Tx queue, and transmit immediately  (char * data, int width, bool transmit_now)&lt;br /&gt;
&lt;br /&gt;
while(!(nrf24l01_irq_pin_active() &amp;amp;&amp;amp; nrf24l01_irq_tx_ds_active())); //wait until IRQ status tells us that it is done transmitting&lt;br /&gt;
&lt;br /&gt;
nrf24l01_irq_clear_all(); //clear all interrupts in the 24L01&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A fully functional [[media:nrf-tx.c|transmitter c-file]] is available. It is intended to work with the receiving code file, available below, and allows for a variable payload.&lt;br /&gt;
&lt;br /&gt;
===Receiver Code===&lt;br /&gt;
Similarly, receiving data from a wireless link requires three steps:&lt;br /&gt;
*initialize nrf24L01+ as receiver&lt;br /&gt;
*wait for incoming packet&lt;br /&gt;
*write packet to memory&lt;br /&gt;
&lt;br /&gt;
That would look like: &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
char data; //variable to recieve incoming data&lt;br /&gt;
int width = 1; //width of payload&lt;br /&gt;
&lt;br /&gt;
nrf24l01_initialize_debug(true, width, false); //initialize the 24L01 to the debug configuration as RX, 1  data byte, and auto-ack disabled&lt;br /&gt;
&lt;br /&gt;
while(!(nrf24l01_irq_pin_active() &amp;amp;&amp;amp; nrf24l01_irq_rx_dr_active())); //wait to receive a packet&lt;br /&gt;
&lt;br /&gt;
nrf24l01_read_rx_payload(&amp;amp;data, width); //get the payload into data&lt;br /&gt;
&lt;br /&gt;
nrf24l01_irq_clear_all(); //clear interrupts&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A fully functional [[media:nrf-rx.c|receiver c-file]] is available. It is intended to work with the transmitter code file, available above, and allows for a variable payload.&lt;br /&gt;
&lt;br /&gt;
===Handling Multi-byte Payloads===&lt;br /&gt;
Transmitting and receiving payloads of widths larger than one byte are handled the same exact way as described as above, except that instead of having a a single char data variable, you would have an array of chars as your data variable. Then rather then pass in the memory of address of &amp;lt;code&amp;gt;data &amp;lt;/code&amp;gt; you can simply pass in &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt; itself,  because in C, the variable representing an array is synonymous with the memory address of its first element. Examples of this are available in the attached C files.&lt;br /&gt;
&lt;br /&gt;
===Bidirectional Communication===&lt;br /&gt;
While technically the nrf24l01+ chip can only be in one mode (transmitting/receiving) at a given instant, with some clever programming you can still get a bidirectional link established between two chips. The [[media:nrf-bidirectional.c| full code for bidirectional communication]] is available on this page. Basically, the chip sits in receiver mode, listening for any incoming packets. If it receives one, it displays it to the screen. However, there in the event that a key is pressed on the local terminal, the PIC switches the mode from receiving to transmitting, transmits the data received locally, and then goes back to receiver mode.   It is not a perfect system because if a packet reaches a chip while the chip is in the middle of transmitting a packet itself, it will not pick up the packet in the air. However, the chance of this sort of situation happening would be rare, depending on the application of the system. &lt;br /&gt;
&lt;br /&gt;
To establish a bidirectional link, both PICs should have the same bidirectional c-file loaded (but this is not necessary: e.g. one PIC could only be able to transmit, and it would still be a viable one-way link ). If the on air data rate is set to 1 Mbps, then this bidirectional c-file is compatible with the [http://www.sparkfun.com/commerce/product_info.php?products_id=9019 Nordic USB Serial Converter] (note that the Nordic USB-Serial converter is only compatible with a payload width of four bytes). The payload width of the bidirectional link can be adjusted with the &amp;quot;[&amp;quot; and &amp;quot;]&amp;quot; keys, exactly as with the above code.&lt;br /&gt;
&lt;br /&gt;
==Data Rates==&lt;br /&gt;
&lt;br /&gt;
Basic timed tests were done to find out how long it took to transmit and receive different sized payloads. These tests were done by sending a packet wirelessly, then timing how long it took to get it back. A pin was raised to high while waiting and then dropped when it was received. These periods were then measured on an oscilloscope, and then averaged. The times used were only those that had 100% return rate. However, the accuracy of these packets was not checked beyond the built in CRC error-checking within the packets themselves. The rates here are to go send out a transmission and then receive it back, so the rate should be doubled for only transmitting in one direction.&lt;br /&gt;
[[Image:bps-nrf24l01.jpg|center]]&lt;/div&gt;</summary>
		<author><name>AndrewKessler</name></author>
	</entry>
	<entry>
		<id>https://hades.mech.northwestern.edu//index.php?title=PIC32MX:_High-speed_Wireless_Communication&amp;diff=19007</id>
		<title>PIC32MX: High-speed Wireless Communication</title>
		<link rel="alternate" type="text/html" href="https://hades.mech.northwestern.edu//index.php?title=PIC32MX:_High-speed_Wireless_Communication&amp;diff=19007"/>
		<updated>2010-08-26T21:38:12Z</updated>

		<summary type="html">&lt;p&gt;AndrewKessler: /* Transmitter Code */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Overview ==&lt;br /&gt;
&lt;br /&gt;
[[Image:nrf-pic1.jpg|thumb|nrf24L01+ wireless chip with pins attatched]]&lt;br /&gt;
This wiki describes how to wire a [http://www.sparkfun.com/commerce/product_info.php?products_id=691 nRF24L01+ chip] (&amp;quot;wireless chip&amp;quot;) to a PIC32 board and includes annotated code describing the functions that facilitate the transmitting and receiving of wireless data. A  [[media:Wireless-ppt.pdf|PowerPoint presentation]] covering much of the introductory information available on this page is also available. &lt;br /&gt;
&lt;br /&gt;
To operate the system, you must properly connect the wireless chips to the PIC32s, load the transmitter code onto the PIC that you wish to act as a transmitter, load the receiver code onto the PIC that you wish to act as a receiver, properly connect an RS232 cable to the PIC and open a serial communication program (e.g. HyperTerminal or [http://chiark.greenend.org.uk/~sgtatham/putty/download.html putty]), and turn the NU32 boards on. If you use the c-files provided on this pages (and everything else is set up properly), the transmitting PIC will broadcast  any characters received from the PC via RS232, and the receiving PIC will display what it receives from wireless link on the PC via RS232. The payload width can be adjusted using the &amp;quot;[&amp;quot; and &amp;quot;]&amp;quot; keys on both the transmitting and receiving PICs. Both wireless chips must be set to the same payload width in order to communicate. Payload widths may vary from 1 to 32. The transmitting PIC will not transmit until enough characters have been entered to fill a payload. Once enough characters have been entered into the transmitting PIC, the serial display will move to a new line to signal transmission.&lt;br /&gt;
&lt;br /&gt;
==Chip Basics==&lt;br /&gt;
The nrf24L01+ Module is a breakout of the nrf24L01+ 2.4 GHz transceiver, with an on board antenna. In order to get a wireless link up and running, the following parameters must be consistent between a transmitter and receiver chip:&lt;br /&gt;
&lt;br /&gt;
===Channels===&lt;br /&gt;
The channel of the nrf24L01+ chip is the frequency that it broadcasts and receives data from. The channel can range from 2.4 GHz to 2.525 GHz, at intervals no more than 1 MHz. The exact distance between channels is dependent on the on air data rate. Two wireless chips must be tuned to the same channel in order to communicate.  See the Air Data Rate section for necessary channel spacing.&lt;br /&gt;
&lt;br /&gt;
===Air Data Rate===&lt;br /&gt;
The air data rate is the rate at which the chip transmits bits wirelessly (and the rate at which it looks for them). The nrf24L01+ chip has three selectable data rates: 250 kbps, 1 Mbps, and 2 Mbps. Faster data rates draw less current, but require a greater distance between channels. Slower data rates give you the option of more channels and better receiver sensitivity, for the obvious trade off of speed. Data rates of 250 kbps and 1 Mbps require channel spacing of at least 1 MHz (allowing for 125 unique channels), and a data rate of 2 Mbps requires spacing of 2 MHz between channels (allowing for 62 channels).  Two wireless chips will not be able to communicate if they are not set to the same on air data rate.&lt;br /&gt;
&lt;br /&gt;
===Payload Width===&lt;br /&gt;
The payload is the actual data you are trying to send over a wireless link, and the payload width is how many bytes are contained within each payload. The nfr24L01+ is capable of supporting payloads up to 32 bytes. A transmitter and receiver must be set to the same payload in order to communicate. Transmission speeds for different sizes payloads are analyzed below. &lt;br /&gt;
&lt;br /&gt;
===Addresses &amp;amp; Pipes===&lt;br /&gt;
Every wireless transmission is preceded by the address of the intended receiver. The nrf24L01+ chip has 6 different receiving pipes, which means it may act as 6 receivers with 6 different addresses. Addresses may be three, four, or five bytes long. The addresses for pipe 0 and 1 may be completely different, but the addresses for pipes 2, 3, and 4 may only differ from the address of pipe 1 by their least significant byte. All active pipes feed into the same 3-packet-deep  incoming transmission queue.  Each pipe may also be set to a expect a different payload width.&lt;br /&gt;
&lt;br /&gt;
== Circuit ==&lt;br /&gt;
&lt;br /&gt;
[[Image:Wireless-circuit.jpg|thumb|Schematic of the nRF24L01+ connected to the PIC32_NU32 board]]&lt;br /&gt;
&lt;br /&gt;
The wireless chip has 8 pins that need to be wired to the PIC (all I/O are relative to PIC):&lt;br /&gt;
&lt;br /&gt;
*Vcc: +3.3 Vdc supply&amp;lt;br&amp;gt;&lt;br /&gt;
*CE:  uC pin C1 (input)&amp;lt;br&amp;gt;&lt;br /&gt;
*CSN: uC pin C2 (output) &amp;lt;br&amp;gt;&lt;br /&gt;
*SCK: uC pin D10, configured as SCK(SPI) (output)&amp;lt;br&amp;gt;&lt;br /&gt;
*MOSI: uC pin D0, configured as SDO(SPI) (output) &amp;lt;br&amp;gt;&lt;br /&gt;
*MISO: uC pin C4, configured as SDI(SPI) (input)&amp;lt;br&amp;gt;&lt;br /&gt;
*IRQ: uC pin B0 (input) &amp;lt;br&amp;gt;&lt;br /&gt;
*GND: common digital ground&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The +3.3V and ground are provided by the NU32 board. The term &amp;quot;uC&amp;quot; above stands for microcontroller, which is the PIC32 in our case. &lt;br /&gt;
&lt;br /&gt;
Descriptions of the wireless chip&amp;#039;s pins can be found in Brennan Ball&amp;#039;s DIYembedded [http://www.diyembedded.com/tutorials/nrf24l01_0/nrf24l01_tutorial_0.pdf Tutorial 0]. The SCK, MOSI, and MISO pins interface with the SPI on the PIC32 which allows for communication between the PIC and the wireless chip. The GPIO pins will be initialized as digital inputs or outputs in the code to enable/disable the wireless chip and check the wireless data transfer/receive stats.&lt;br /&gt;
&lt;br /&gt;
In order to print information from the PIC to the PC, we need to wire an [[PIC_RS232]] cable&amp;#039;s transfer and receive lines to the UART ports of the NU32 board (F4, F5).&lt;br /&gt;
&lt;br /&gt;
==Code==&lt;br /&gt;
&lt;br /&gt;
===Driver===&lt;br /&gt;
Besides the main C files for the transmitter and receiver, the project also needs the [[media:Wireless-files.zip|nRF24L01.h header file and C file]]. These driver files were created by Brennan Ball, and are explained in detail in his [http://blog.diyembedded.com/ tutorials]. The following things must be changed in the header file available on his website to make it compatible with the NU32 board:&lt;br /&gt;
*pin registers and masks must be set to the appropriate values&lt;br /&gt;
*the &amp;quot;HardwareProfile.h&amp;quot; NU32 specific file must be included &lt;br /&gt;
&lt;br /&gt;
These changes are accounted for the the driver available on this page. All of the SPI functions trace back to a single function to send and read a single byte, which must be defined in the main c file. &lt;br /&gt;
&lt;br /&gt;
This function is available here: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 unsigned char spi_send_read_byte(unsigned char byte) {&lt;br /&gt;
  	 unsigned short	txData, rxData; // transmit, receive characters&lt;br /&gt;
   	 int chn = 1; // SPI channel to use (1 or 2)&lt;br /&gt;
  	 &lt;br /&gt;
   	 txData = byte; // take inputted byte and store into txData   &lt;br /&gt;
   	 SpiChnPutC(chn, txData);			// send data&lt;br /&gt;
 	 rxData = SpiChnGetC(chn);			// retreive over channel chn the received data into rxData&lt;br /&gt;
    &lt;br /&gt;
  	 return rxData; &lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
===Initialization Functions===&lt;br /&gt;
In order to get a wireless link up and running, you will need to initialize both the wireless chip and SPI communication on the PIC. &lt;br /&gt;
To intialize SPI on the PIC, create the following function in your main C file:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;oid SpiInitDevice(int chn, int isMaster, int frmEn, int frmMaster) {&lt;br /&gt;
   	 unsigned int config = SPI_CON_MODE8|SPI_CON_SMP|SPI_CON_ON;	// SPI configuration word&lt;br /&gt;
   	 if(isMaster)&lt;br /&gt;
   	 {&lt;br /&gt;
   		 config|=SPI_CON_MSTEN;&lt;br /&gt;
   	 }&lt;br /&gt;
   	 if(frmEn)&lt;br /&gt;
   	 {&lt;br /&gt;
   		 config|=SPI_CON_FRMEN;&lt;br /&gt;
   		 if(!frmMaster) {   &lt;br /&gt;
   			 config|=SPI_CON_FRMSYNC;&lt;br /&gt;
      	 }&lt;br /&gt;
   	 }&lt;br /&gt;
  	 SpiChnOpen(chn, config, 4);	// divide fpb by 4, configure the I/O ports. Not using SS in this example&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
You can then call this function with the call &amp;lt;code&amp;gt; SpiInitDevice(1,1,0,0) &amp;lt;/code&amp;gt; to initalize SPI channel 1 on the PIC. &lt;br /&gt;
&lt;br /&gt;
To initialize the nrf24L01+ chip itself, you have to options. You can either use &amp;lt;code&amp;gt; nrf24L01_initialize(..) &amp;lt;/code&amp;gt; which gives  you the opportunity to manually define every register in the chip right from the start. However, this function has 21 arguments, so it is not the most convenient to use if you don&amp;#039;t have to. Instead, you can use &amp;lt;code&amp;gt; nrf24L01_initialize_debug(bool rx, int width, bool auto_ack_on) &amp;lt;/code&amp;gt;, which gives you the option to specify whether or not the chip is a receiver or transmitter, what the payload width is, and whether or not to enable auto-acknowledge. However, it limits you to Pipe 0, an air data rate of 2 Mpbs, and RF Channel 2. However, these limitations can be adjusted easily after initialization using additional functions (see the library for all available functions). So, for example, to initialize your chip as a transmitter with a payload width of one byte and no auto-acknowledgement, you could call &amp;lt;code&amp;gt; nrf24L01_initialize_debug(0,1,0)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If you wish to display information to the screen or receive information from the keyboard, you will have to initialize the RS232 connection as well. This can be done with the following code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
int	pbClk = SYSTEMConfigPerformance(SYS_FREQ);&lt;br /&gt;
initUART2(pbClk);&lt;br /&gt;
&lt;br /&gt;
 void initUART2(int pbClk) {&lt;br /&gt;
  	 #define config1 	UART_EN | UART_IDLE_CON | UART_RX_TX | UART_DIS_WAKE | UART_DIS_LOOPBACK | UART_DIS_ABAUD | UART_NO_PAR_8BIT | UART_1STOPBIT | UART_IRDA_DIS | UART_DIS_BCLK_CTS_RTS| UART_NORMAL_RX | UART_BRGH_SIXTEEN&lt;br /&gt;
  	 #define config2		UART_TX_PIN_LOW | UART_RX_ENABLE | UART_TX_ENABLE | UART_INT_TX | UART_INT_RX_CHAR | UART_ADR_DETECT_DIS | UART_RX_OVERRUN_CLEAR	&lt;br /&gt;
   	 OpenUART2( config1, config2, pbClk/16/DESIRED_BAUDRATE-1);	// calculate actual BAUD generate value.&lt;br /&gt;
   	 ConfigIntUART2(UART_INT_PR2 | UART_RX_INT_EN);&lt;br /&gt;
   	 //INTEnableSystemMultiVectoredInt();&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Transmitter Code===&lt;br /&gt;
&lt;br /&gt;
Wirelessly transmitting data requires three steps:&lt;br /&gt;
&lt;br /&gt;
*initialize nrf24L01+ as transmitter&lt;br /&gt;
*transmit packet&lt;br /&gt;
*wait for payload to be sent&lt;br /&gt;
&lt;br /&gt;
A basic outline for such a procedure would look like:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
char data = &amp;#039;x&amp;#039;; //data to send&lt;br /&gt;
int width = 1; //width of payload&lt;br /&gt;
&lt;br /&gt;
nrf24l01_initialize_debug(false, width, false); //initialize the 24L01 to the debug configuration as TX, 1  data byte, and auto-ack disabled&lt;br /&gt;
&lt;br /&gt;
nrf24l01_write_tx_payload(&amp;amp;data, width, true); //add char to Tx queue, and transmit immediately  (char * data, int width, bool transmit_now)&lt;br /&gt;
&lt;br /&gt;
while(!(nrf24l01_irq_pin_active() &amp;amp;&amp;amp; nrf24l01_irq_tx_ds_active())); //wait until IRQ status tells us that it is done transmitting&lt;br /&gt;
&lt;br /&gt;
nrf24l01_irq_clear_all(); //clear all interrupts in the 24L01&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A fully functional [[media:nrf-tx.c|transmitter c-file]] is available. It is intended to work with the receiving code file, available below, and allows for a variable payload.&lt;br /&gt;
&lt;br /&gt;
===Receiver Code===&lt;br /&gt;
Similarly, receiving data from a wireless link requires three steps:&lt;br /&gt;
*initialize nrf24L01+ as receiver&lt;br /&gt;
*wait for incoming packet&lt;br /&gt;
*write packet to memory&lt;br /&gt;
&lt;br /&gt;
That would look like: &lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;lt;code&amp;gt;&lt;br /&gt;
char data; //variable to recieve incoming data&lt;br /&gt;
int width = 1; //width of payload&lt;br /&gt;
&lt;br /&gt;
nrf24l01_initialize_debug(true, width, false); //initialize the 24L01 to the debug configuration as RX, 1  data byte, and auto-ack disabled&lt;br /&gt;
&lt;br /&gt;
while(!(nrf24l01_irq_pin_active() &amp;amp;&amp;amp; nrf24l01_irq_rx_dr_active())); //wait to receive a packet&lt;br /&gt;
&lt;br /&gt;
nrf24l01_read_rx_payload(&amp;amp;data, width); //get the payload into data&lt;br /&gt;
&lt;br /&gt;
nrf24l01_irq_clear_all(); //clear interrupts&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A fully functional [[media:nrf-rx.c|receiver c-file]] is available. It is intended to work with the transmitter code file, available above, and allows for a variable payload.&lt;br /&gt;
&lt;br /&gt;
===Handling Multi-byte Payloads===&lt;br /&gt;
Transmitting and receiving payloads of widths larger than one byte are handled the same exact way as described as above, except that instead of having a a single char data variable, you would have an array of chars as your data variable. Then rather then pass in the memory of address of &amp;lt;code&amp;gt;data &amp;lt;/code&amp;gt; you can simply pass in &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt; itself,  because in C, the variable representing an array is synonymous with the memory address of its first element. Examples of this are available in the attached C files.&lt;br /&gt;
&lt;br /&gt;
===Bidirectional Communication===&lt;br /&gt;
While technically the nrf24l01+ chip can only be in one mode (transmitting/receiving) at a given instant, with some clever programming you can still get a bidirectional link established between two chips. The [[media:nrf-bidirectional.c| full code for bidirectional communication]] is available on this page. Basically, the chip sits in receiver mode, listening for any incoming packets. If it receives one, it displays it to the screen. However, there in the event that a key is pressed on the local terminal, the PIC switches the mode from receiving to transmitting, transmits the data received locally, and then goes back to receiver mode.   It is not a perfect system because if a packet reaches a chip while the chip is in the middle of transmitting a packet itself, it will not pick up the packet in the air. However, the chance of this sort of situation happening would be rare, depending on the application of the system. &lt;br /&gt;
&lt;br /&gt;
To establish a bidirectional link, both PICs should have the same bidirectional c-file loaded (but this is not necessary: e.g. one PIC could only be able to transmit, and it would still be a viable one-way link ). If the on air data rate is set to 1 Mbps, then this bidirectional c-file is compatible with the [http://www.sparkfun.com/commerce/product_info.php?products_id=9019 Nordic USB Serial Converter] (note that the Nordic USB-Serial converter is only compatible with a payload width of four bytes). The payload width of the bidirectional link can be adjusted with the &amp;quot;[&amp;quot; and &amp;quot;]&amp;quot; keys, exactly as with the above code.&lt;br /&gt;
&lt;br /&gt;
==Data Rates==&lt;br /&gt;
&lt;br /&gt;
Basic timed tests were done to find out how long it took to transmit and receive different sized payloads. These tests were done by sending a packet wirelessly, then timing how long it took to get it back. A pin was raised to high while waiting and then dropped when it was received. These periods were then measured on an oscilloscope, and then averaged. The times used were only those that had 100% return rate. However, the accuracy of these packets was not checked beyond the built in CRC error-checking within the packets themselves. The rates here are to go send out a transmission and then receive it back, so the rate should be doubled for only transmitting in one direction.&lt;br /&gt;
[[Image:bps-nrf24l01.jpg|center]]&lt;/div&gt;</summary>
		<author><name>AndrewKessler</name></author>
	</entry>
	<entry>
		<id>https://hades.mech.northwestern.edu//index.php?title=PIC32MX:_High-speed_Wireless_Communication&amp;diff=19006</id>
		<title>PIC32MX: High-speed Wireless Communication</title>
		<link rel="alternate" type="text/html" href="https://hades.mech.northwestern.edu//index.php?title=PIC32MX:_High-speed_Wireless_Communication&amp;diff=19006"/>
		<updated>2010-08-26T21:37:49Z</updated>

		<summary type="html">&lt;p&gt;AndrewKessler: /* Receiver Code */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Overview ==&lt;br /&gt;
&lt;br /&gt;
[[Image:nrf-pic1.jpg|thumb|nrf24L01+ wireless chip with pins attatched]]&lt;br /&gt;
This wiki describes how to wire a [http://www.sparkfun.com/commerce/product_info.php?products_id=691 nRF24L01+ chip] (&amp;quot;wireless chip&amp;quot;) to a PIC32 board and includes annotated code describing the functions that facilitate the transmitting and receiving of wireless data. A  [[media:Wireless-ppt.pdf|PowerPoint presentation]] covering much of the introductory information available on this page is also available. &lt;br /&gt;
&lt;br /&gt;
To operate the system, you must properly connect the wireless chips to the PIC32s, load the transmitter code onto the PIC that you wish to act as a transmitter, load the receiver code onto the PIC that you wish to act as a receiver, properly connect an RS232 cable to the PIC and open a serial communication program (e.g. HyperTerminal or [http://chiark.greenend.org.uk/~sgtatham/putty/download.html putty]), and turn the NU32 boards on. If you use the c-files provided on this pages (and everything else is set up properly), the transmitting PIC will broadcast  any characters received from the PC via RS232, and the receiving PIC will display what it receives from wireless link on the PC via RS232. The payload width can be adjusted using the &amp;quot;[&amp;quot; and &amp;quot;]&amp;quot; keys on both the transmitting and receiving PICs. Both wireless chips must be set to the same payload width in order to communicate. Payload widths may vary from 1 to 32. The transmitting PIC will not transmit until enough characters have been entered to fill a payload. Once enough characters have been entered into the transmitting PIC, the serial display will move to a new line to signal transmission.&lt;br /&gt;
&lt;br /&gt;
==Chip Basics==&lt;br /&gt;
The nrf24L01+ Module is a breakout of the nrf24L01+ 2.4 GHz transceiver, with an on board antenna. In order to get a wireless link up and running, the following parameters must be consistent between a transmitter and receiver chip:&lt;br /&gt;
&lt;br /&gt;
===Channels===&lt;br /&gt;
The channel of the nrf24L01+ chip is the frequency that it broadcasts and receives data from. The channel can range from 2.4 GHz to 2.525 GHz, at intervals no more than 1 MHz. The exact distance between channels is dependent on the on air data rate. Two wireless chips must be tuned to the same channel in order to communicate.  See the Air Data Rate section for necessary channel spacing.&lt;br /&gt;
&lt;br /&gt;
===Air Data Rate===&lt;br /&gt;
The air data rate is the rate at which the chip transmits bits wirelessly (and the rate at which it looks for them). The nrf24L01+ chip has three selectable data rates: 250 kbps, 1 Mbps, and 2 Mbps. Faster data rates draw less current, but require a greater distance between channels. Slower data rates give you the option of more channels and better receiver sensitivity, for the obvious trade off of speed. Data rates of 250 kbps and 1 Mbps require channel spacing of at least 1 MHz (allowing for 125 unique channels), and a data rate of 2 Mbps requires spacing of 2 MHz between channels (allowing for 62 channels).  Two wireless chips will not be able to communicate if they are not set to the same on air data rate.&lt;br /&gt;
&lt;br /&gt;
===Payload Width===&lt;br /&gt;
The payload is the actual data you are trying to send over a wireless link, and the payload width is how many bytes are contained within each payload. The nfr24L01+ is capable of supporting payloads up to 32 bytes. A transmitter and receiver must be set to the same payload in order to communicate. Transmission speeds for different sizes payloads are analyzed below. &lt;br /&gt;
&lt;br /&gt;
===Addresses &amp;amp; Pipes===&lt;br /&gt;
Every wireless transmission is preceded by the address of the intended receiver. The nrf24L01+ chip has 6 different receiving pipes, which means it may act as 6 receivers with 6 different addresses. Addresses may be three, four, or five bytes long. The addresses for pipe 0 and 1 may be completely different, but the addresses for pipes 2, 3, and 4 may only differ from the address of pipe 1 by their least significant byte. All active pipes feed into the same 3-packet-deep  incoming transmission queue.  Each pipe may also be set to a expect a different payload width.&lt;br /&gt;
&lt;br /&gt;
== Circuit ==&lt;br /&gt;
&lt;br /&gt;
[[Image:Wireless-circuit.jpg|thumb|Schematic of the nRF24L01+ connected to the PIC32_NU32 board]]&lt;br /&gt;
&lt;br /&gt;
The wireless chip has 8 pins that need to be wired to the PIC (all I/O are relative to PIC):&lt;br /&gt;
&lt;br /&gt;
*Vcc: +3.3 Vdc supply&amp;lt;br&amp;gt;&lt;br /&gt;
*CE:  uC pin C1 (input)&amp;lt;br&amp;gt;&lt;br /&gt;
*CSN: uC pin C2 (output) &amp;lt;br&amp;gt;&lt;br /&gt;
*SCK: uC pin D10, configured as SCK(SPI) (output)&amp;lt;br&amp;gt;&lt;br /&gt;
*MOSI: uC pin D0, configured as SDO(SPI) (output) &amp;lt;br&amp;gt;&lt;br /&gt;
*MISO: uC pin C4, configured as SDI(SPI) (input)&amp;lt;br&amp;gt;&lt;br /&gt;
*IRQ: uC pin B0 (input) &amp;lt;br&amp;gt;&lt;br /&gt;
*GND: common digital ground&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The +3.3V and ground are provided by the NU32 board. The term &amp;quot;uC&amp;quot; above stands for microcontroller, which is the PIC32 in our case. &lt;br /&gt;
&lt;br /&gt;
Descriptions of the wireless chip&amp;#039;s pins can be found in Brennan Ball&amp;#039;s DIYembedded [http://www.diyembedded.com/tutorials/nrf24l01_0/nrf24l01_tutorial_0.pdf Tutorial 0]. The SCK, MOSI, and MISO pins interface with the SPI on the PIC32 which allows for communication between the PIC and the wireless chip. The GPIO pins will be initialized as digital inputs or outputs in the code to enable/disable the wireless chip and check the wireless data transfer/receive stats.&lt;br /&gt;
&lt;br /&gt;
In order to print information from the PIC to the PC, we need to wire an [[PIC_RS232]] cable&amp;#039;s transfer and receive lines to the UART ports of the NU32 board (F4, F5).&lt;br /&gt;
&lt;br /&gt;
==Code==&lt;br /&gt;
&lt;br /&gt;
===Driver===&lt;br /&gt;
Besides the main C files for the transmitter and receiver, the project also needs the [[media:Wireless-files.zip|nRF24L01.h header file and C file]]. These driver files were created by Brennan Ball, and are explained in detail in his [http://blog.diyembedded.com/ tutorials]. The following things must be changed in the header file available on his website to make it compatible with the NU32 board:&lt;br /&gt;
*pin registers and masks must be set to the appropriate values&lt;br /&gt;
*the &amp;quot;HardwareProfile.h&amp;quot; NU32 specific file must be included &lt;br /&gt;
&lt;br /&gt;
These changes are accounted for the the driver available on this page. All of the SPI functions trace back to a single function to send and read a single byte, which must be defined in the main c file. &lt;br /&gt;
&lt;br /&gt;
This function is available here: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 unsigned char spi_send_read_byte(unsigned char byte) {&lt;br /&gt;
  	 unsigned short	txData, rxData; // transmit, receive characters&lt;br /&gt;
   	 int chn = 1; // SPI channel to use (1 or 2)&lt;br /&gt;
  	 &lt;br /&gt;
   	 txData = byte; // take inputted byte and store into txData   &lt;br /&gt;
   	 SpiChnPutC(chn, txData);			// send data&lt;br /&gt;
 	 rxData = SpiChnGetC(chn);			// retreive over channel chn the received data into rxData&lt;br /&gt;
    &lt;br /&gt;
  	 return rxData; &lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
===Initialization Functions===&lt;br /&gt;
In order to get a wireless link up and running, you will need to initialize both the wireless chip and SPI communication on the PIC. &lt;br /&gt;
To intialize SPI on the PIC, create the following function in your main C file:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;oid SpiInitDevice(int chn, int isMaster, int frmEn, int frmMaster) {&lt;br /&gt;
   	 unsigned int config = SPI_CON_MODE8|SPI_CON_SMP|SPI_CON_ON;	// SPI configuration word&lt;br /&gt;
   	 if(isMaster)&lt;br /&gt;
   	 {&lt;br /&gt;
   		 config|=SPI_CON_MSTEN;&lt;br /&gt;
   	 }&lt;br /&gt;
   	 if(frmEn)&lt;br /&gt;
   	 {&lt;br /&gt;
   		 config|=SPI_CON_FRMEN;&lt;br /&gt;
   		 if(!frmMaster) {   &lt;br /&gt;
   			 config|=SPI_CON_FRMSYNC;&lt;br /&gt;
      	 }&lt;br /&gt;
   	 }&lt;br /&gt;
  	 SpiChnOpen(chn, config, 4);	// divide fpb by 4, configure the I/O ports. Not using SS in this example&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
You can then call this function with the call &amp;lt;code&amp;gt; SpiInitDevice(1,1,0,0) &amp;lt;/code&amp;gt; to initalize SPI channel 1 on the PIC. &lt;br /&gt;
&lt;br /&gt;
To initialize the nrf24L01+ chip itself, you have to options. You can either use &amp;lt;code&amp;gt; nrf24L01_initialize(..) &amp;lt;/code&amp;gt; which gives  you the opportunity to manually define every register in the chip right from the start. However, this function has 21 arguments, so it is not the most convenient to use if you don&amp;#039;t have to. Instead, you can use &amp;lt;code&amp;gt; nrf24L01_initialize_debug(bool rx, int width, bool auto_ack_on) &amp;lt;/code&amp;gt;, which gives you the option to specify whether or not the chip is a receiver or transmitter, what the payload width is, and whether or not to enable auto-acknowledge. However, it limits you to Pipe 0, an air data rate of 2 Mpbs, and RF Channel 2. However, these limitations can be adjusted easily after initialization using additional functions (see the library for all available functions). So, for example, to initialize your chip as a transmitter with a payload width of one byte and no auto-acknowledgement, you could call &amp;lt;code&amp;gt; nrf24L01_initialize_debug(0,1,0)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If you wish to display information to the screen or receive information from the keyboard, you will have to initialize the RS232 connection as well. This can be done with the following code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
int	pbClk = SYSTEMConfigPerformance(SYS_FREQ);&lt;br /&gt;
initUART2(pbClk);&lt;br /&gt;
&lt;br /&gt;
 void initUART2(int pbClk) {&lt;br /&gt;
  	 #define config1 	UART_EN | UART_IDLE_CON | UART_RX_TX | UART_DIS_WAKE | UART_DIS_LOOPBACK | UART_DIS_ABAUD | UART_NO_PAR_8BIT | UART_1STOPBIT | UART_IRDA_DIS | UART_DIS_BCLK_CTS_RTS| UART_NORMAL_RX | UART_BRGH_SIXTEEN&lt;br /&gt;
  	 #define config2		UART_TX_PIN_LOW | UART_RX_ENABLE | UART_TX_ENABLE | UART_INT_TX | UART_INT_RX_CHAR | UART_ADR_DETECT_DIS | UART_RX_OVERRUN_CLEAR	&lt;br /&gt;
   	 OpenUART2( config1, config2, pbClk/16/DESIRED_BAUDRATE-1);	// calculate actual BAUD generate value.&lt;br /&gt;
   	 ConfigIntUART2(UART_INT_PR2 | UART_RX_INT_EN);&lt;br /&gt;
   	 //INTEnableSystemMultiVectoredInt();&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Transmitter Code===&lt;br /&gt;
&lt;br /&gt;
Wirelessly transmitting data requires three steps:&lt;br /&gt;
&lt;br /&gt;
*initialize nrf24L01+ as transmitter&lt;br /&gt;
*transmit packet&lt;br /&gt;
*wait for payload to be sent&lt;br /&gt;
&lt;br /&gt;
A basic outline for such a procedure would look like:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
char data = &amp;#039;x&amp;#039;; //data to send&lt;br /&gt;
int width = 1; //width of payload&lt;br /&gt;
&lt;br /&gt;
nrf24l01_initialize_debug(false, width, false); //initialize the 24L01 to the debug configuration as TX, 1  data byte, and auto-ack disabled&lt;br /&gt;
&lt;br /&gt;
nrf24l01_write_tx_payload(&amp;amp;data, width, true); //add char to Tx queue, and transmit immediately  (char * data, int width, bool transmit_now)&lt;br /&gt;
&lt;br /&gt;
while(!(nrf24l01_irq_pin_active() &amp;amp;&amp;amp; nrf24l01_irq_tx_ds_active())); //wait until IRQ status tells us that it is done transmitting&lt;br /&gt;
&lt;br /&gt;
nrf24l01_irq_clear_all(); //clear all interrupts in the 24L01&lt;br /&gt;
&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A fully functional [[media:nrf-tx.c|transmitter c-file]] is available. It is intended to work with the receiving code file, available below, and allows for a variable payload.&lt;br /&gt;
&lt;br /&gt;
===Receiver Code===&lt;br /&gt;
Similarly, receiving data from a wireless link requires three steps:&lt;br /&gt;
*initialize nrf24L01+ as receiver&lt;br /&gt;
*wait for incoming packet&lt;br /&gt;
*write packet to memory&lt;br /&gt;
&lt;br /&gt;
That would look like: &lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;lt;code&amp;gt;&lt;br /&gt;
char data; //variable to recieve incoming data&lt;br /&gt;
int width = 1; //width of payload&lt;br /&gt;
&lt;br /&gt;
nrf24l01_initialize_debug(true, width, false); //initialize the 24L01 to the debug configuration as RX, 1  data byte, and auto-ack disabled&lt;br /&gt;
&lt;br /&gt;
while(!(nrf24l01_irq_pin_active() &amp;amp;&amp;amp; nrf24l01_irq_rx_dr_active())); //wait to receive a packet&lt;br /&gt;
&lt;br /&gt;
nrf24l01_read_rx_payload(&amp;amp;data, width); //get the payload into data&lt;br /&gt;
&lt;br /&gt;
nrf24l01_irq_clear_all(); //clear interrupts&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A fully functional [[media:nrf-rx.c|receiver c-file]] is available. It is intended to work with the transmitter code file, available above, and allows for a variable payload.&lt;br /&gt;
&lt;br /&gt;
===Handling Multi-byte Payloads===&lt;br /&gt;
Transmitting and receiving payloads of widths larger than one byte are handled the same exact way as described as above, except that instead of having a a single char data variable, you would have an array of chars as your data variable. Then rather then pass in the memory of address of &amp;lt;code&amp;gt;data &amp;lt;/code&amp;gt; you can simply pass in &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt; itself,  because in C, the variable representing an array is synonymous with the memory address of its first element. Examples of this are available in the attached C files.&lt;br /&gt;
&lt;br /&gt;
===Bidirectional Communication===&lt;br /&gt;
While technically the nrf24l01+ chip can only be in one mode (transmitting/receiving) at a given instant, with some clever programming you can still get a bidirectional link established between two chips. The [[media:nrf-bidirectional.c| full code for bidirectional communication]] is available on this page. Basically, the chip sits in receiver mode, listening for any incoming packets. If it receives one, it displays it to the screen. However, there in the event that a key is pressed on the local terminal, the PIC switches the mode from receiving to transmitting, transmits the data received locally, and then goes back to receiver mode.   It is not a perfect system because if a packet reaches a chip while the chip is in the middle of transmitting a packet itself, it will not pick up the packet in the air. However, the chance of this sort of situation happening would be rare, depending on the application of the system. &lt;br /&gt;
&lt;br /&gt;
To establish a bidirectional link, both PICs should have the same bidirectional c-file loaded (but this is not necessary: e.g. one PIC could only be able to transmit, and it would still be a viable one-way link ). If the on air data rate is set to 1 Mbps, then this bidirectional c-file is compatible with the [http://www.sparkfun.com/commerce/product_info.php?products_id=9019 Nordic USB Serial Converter] (note that the Nordic USB-Serial converter is only compatible with a payload width of four bytes). The payload width of the bidirectional link can be adjusted with the &amp;quot;[&amp;quot; and &amp;quot;]&amp;quot; keys, exactly as with the above code.&lt;br /&gt;
&lt;br /&gt;
==Data Rates==&lt;br /&gt;
&lt;br /&gt;
Basic timed tests were done to find out how long it took to transmit and receive different sized payloads. These tests were done by sending a packet wirelessly, then timing how long it took to get it back. A pin was raised to high while waiting and then dropped when it was received. These periods were then measured on an oscilloscope, and then averaged. The times used were only those that had 100% return rate. However, the accuracy of these packets was not checked beyond the built in CRC error-checking within the packets themselves. The rates here are to go send out a transmission and then receive it back, so the rate should be doubled for only transmitting in one direction.&lt;br /&gt;
[[Image:bps-nrf24l01.jpg|center]]&lt;/div&gt;</summary>
		<author><name>AndrewKessler</name></author>
	</entry>
	<entry>
		<id>https://hades.mech.northwestern.edu//index.php?title=PIC32MX:_High-speed_Wireless_Communication&amp;diff=19005</id>
		<title>PIC32MX: High-speed Wireless Communication</title>
		<link rel="alternate" type="text/html" href="https://hades.mech.northwestern.edu//index.php?title=PIC32MX:_High-speed_Wireless_Communication&amp;diff=19005"/>
		<updated>2010-08-26T21:37:25Z</updated>

		<summary type="html">&lt;p&gt;AndrewKessler: /* Transmitter Code */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Overview ==&lt;br /&gt;
&lt;br /&gt;
[[Image:nrf-pic1.jpg|thumb|nrf24L01+ wireless chip with pins attatched]]&lt;br /&gt;
This wiki describes how to wire a [http://www.sparkfun.com/commerce/product_info.php?products_id=691 nRF24L01+ chip] (&amp;quot;wireless chip&amp;quot;) to a PIC32 board and includes annotated code describing the functions that facilitate the transmitting and receiving of wireless data. A  [[media:Wireless-ppt.pdf|PowerPoint presentation]] covering much of the introductory information available on this page is also available. &lt;br /&gt;
&lt;br /&gt;
To operate the system, you must properly connect the wireless chips to the PIC32s, load the transmitter code onto the PIC that you wish to act as a transmitter, load the receiver code onto the PIC that you wish to act as a receiver, properly connect an RS232 cable to the PIC and open a serial communication program (e.g. HyperTerminal or [http://chiark.greenend.org.uk/~sgtatham/putty/download.html putty]), and turn the NU32 boards on. If you use the c-files provided on this pages (and everything else is set up properly), the transmitting PIC will broadcast  any characters received from the PC via RS232, and the receiving PIC will display what it receives from wireless link on the PC via RS232. The payload width can be adjusted using the &amp;quot;[&amp;quot; and &amp;quot;]&amp;quot; keys on both the transmitting and receiving PICs. Both wireless chips must be set to the same payload width in order to communicate. Payload widths may vary from 1 to 32. The transmitting PIC will not transmit until enough characters have been entered to fill a payload. Once enough characters have been entered into the transmitting PIC, the serial display will move to a new line to signal transmission.&lt;br /&gt;
&lt;br /&gt;
==Chip Basics==&lt;br /&gt;
The nrf24L01+ Module is a breakout of the nrf24L01+ 2.4 GHz transceiver, with an on board antenna. In order to get a wireless link up and running, the following parameters must be consistent between a transmitter and receiver chip:&lt;br /&gt;
&lt;br /&gt;
===Channels===&lt;br /&gt;
The channel of the nrf24L01+ chip is the frequency that it broadcasts and receives data from. The channel can range from 2.4 GHz to 2.525 GHz, at intervals no more than 1 MHz. The exact distance between channels is dependent on the on air data rate. Two wireless chips must be tuned to the same channel in order to communicate.  See the Air Data Rate section for necessary channel spacing.&lt;br /&gt;
&lt;br /&gt;
===Air Data Rate===&lt;br /&gt;
The air data rate is the rate at which the chip transmits bits wirelessly (and the rate at which it looks for them). The nrf24L01+ chip has three selectable data rates: 250 kbps, 1 Mbps, and 2 Mbps. Faster data rates draw less current, but require a greater distance between channels. Slower data rates give you the option of more channels and better receiver sensitivity, for the obvious trade off of speed. Data rates of 250 kbps and 1 Mbps require channel spacing of at least 1 MHz (allowing for 125 unique channels), and a data rate of 2 Mbps requires spacing of 2 MHz between channels (allowing for 62 channels).  Two wireless chips will not be able to communicate if they are not set to the same on air data rate.&lt;br /&gt;
&lt;br /&gt;
===Payload Width===&lt;br /&gt;
The payload is the actual data you are trying to send over a wireless link, and the payload width is how many bytes are contained within each payload. The nfr24L01+ is capable of supporting payloads up to 32 bytes. A transmitter and receiver must be set to the same payload in order to communicate. Transmission speeds for different sizes payloads are analyzed below. &lt;br /&gt;
&lt;br /&gt;
===Addresses &amp;amp; Pipes===&lt;br /&gt;
Every wireless transmission is preceded by the address of the intended receiver. The nrf24L01+ chip has 6 different receiving pipes, which means it may act as 6 receivers with 6 different addresses. Addresses may be three, four, or five bytes long. The addresses for pipe 0 and 1 may be completely different, but the addresses for pipes 2, 3, and 4 may only differ from the address of pipe 1 by their least significant byte. All active pipes feed into the same 3-packet-deep  incoming transmission queue.  Each pipe may also be set to a expect a different payload width.&lt;br /&gt;
&lt;br /&gt;
== Circuit ==&lt;br /&gt;
&lt;br /&gt;
[[Image:Wireless-circuit.jpg|thumb|Schematic of the nRF24L01+ connected to the PIC32_NU32 board]]&lt;br /&gt;
&lt;br /&gt;
The wireless chip has 8 pins that need to be wired to the PIC (all I/O are relative to PIC):&lt;br /&gt;
&lt;br /&gt;
*Vcc: +3.3 Vdc supply&amp;lt;br&amp;gt;&lt;br /&gt;
*CE:  uC pin C1 (input)&amp;lt;br&amp;gt;&lt;br /&gt;
*CSN: uC pin C2 (output) &amp;lt;br&amp;gt;&lt;br /&gt;
*SCK: uC pin D10, configured as SCK(SPI) (output)&amp;lt;br&amp;gt;&lt;br /&gt;
*MOSI: uC pin D0, configured as SDO(SPI) (output) &amp;lt;br&amp;gt;&lt;br /&gt;
*MISO: uC pin C4, configured as SDI(SPI) (input)&amp;lt;br&amp;gt;&lt;br /&gt;
*IRQ: uC pin B0 (input) &amp;lt;br&amp;gt;&lt;br /&gt;
*GND: common digital ground&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The +3.3V and ground are provided by the NU32 board. The term &amp;quot;uC&amp;quot; above stands for microcontroller, which is the PIC32 in our case. &lt;br /&gt;
&lt;br /&gt;
Descriptions of the wireless chip&amp;#039;s pins can be found in Brennan Ball&amp;#039;s DIYembedded [http://www.diyembedded.com/tutorials/nrf24l01_0/nrf24l01_tutorial_0.pdf Tutorial 0]. The SCK, MOSI, and MISO pins interface with the SPI on the PIC32 which allows for communication between the PIC and the wireless chip. The GPIO pins will be initialized as digital inputs or outputs in the code to enable/disable the wireless chip and check the wireless data transfer/receive stats.&lt;br /&gt;
&lt;br /&gt;
In order to print information from the PIC to the PC, we need to wire an [[PIC_RS232]] cable&amp;#039;s transfer and receive lines to the UART ports of the NU32 board (F4, F5).&lt;br /&gt;
&lt;br /&gt;
==Code==&lt;br /&gt;
&lt;br /&gt;
===Driver===&lt;br /&gt;
Besides the main C files for the transmitter and receiver, the project also needs the [[media:Wireless-files.zip|nRF24L01.h header file and C file]]. These driver files were created by Brennan Ball, and are explained in detail in his [http://blog.diyembedded.com/ tutorials]. The following things must be changed in the header file available on his website to make it compatible with the NU32 board:&lt;br /&gt;
*pin registers and masks must be set to the appropriate values&lt;br /&gt;
*the &amp;quot;HardwareProfile.h&amp;quot; NU32 specific file must be included &lt;br /&gt;
&lt;br /&gt;
These changes are accounted for the the driver available on this page. All of the SPI functions trace back to a single function to send and read a single byte, which must be defined in the main c file. &lt;br /&gt;
&lt;br /&gt;
This function is available here: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 unsigned char spi_send_read_byte(unsigned char byte) {&lt;br /&gt;
  	 unsigned short	txData, rxData; // transmit, receive characters&lt;br /&gt;
   	 int chn = 1; // SPI channel to use (1 or 2)&lt;br /&gt;
  	 &lt;br /&gt;
   	 txData = byte; // take inputted byte and store into txData   &lt;br /&gt;
   	 SpiChnPutC(chn, txData);			// send data&lt;br /&gt;
 	 rxData = SpiChnGetC(chn);			// retreive over channel chn the received data into rxData&lt;br /&gt;
    &lt;br /&gt;
  	 return rxData; &lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
===Initialization Functions===&lt;br /&gt;
In order to get a wireless link up and running, you will need to initialize both the wireless chip and SPI communication on the PIC. &lt;br /&gt;
To intialize SPI on the PIC, create the following function in your main C file:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;oid SpiInitDevice(int chn, int isMaster, int frmEn, int frmMaster) {&lt;br /&gt;
   	 unsigned int config = SPI_CON_MODE8|SPI_CON_SMP|SPI_CON_ON;	// SPI configuration word&lt;br /&gt;
   	 if(isMaster)&lt;br /&gt;
   	 {&lt;br /&gt;
   		 config|=SPI_CON_MSTEN;&lt;br /&gt;
   	 }&lt;br /&gt;
   	 if(frmEn)&lt;br /&gt;
   	 {&lt;br /&gt;
   		 config|=SPI_CON_FRMEN;&lt;br /&gt;
   		 if(!frmMaster) {   &lt;br /&gt;
   			 config|=SPI_CON_FRMSYNC;&lt;br /&gt;
      	 }&lt;br /&gt;
   	 }&lt;br /&gt;
  	 SpiChnOpen(chn, config, 4);	// divide fpb by 4, configure the I/O ports. Not using SS in this example&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
You can then call this function with the call &amp;lt;code&amp;gt; SpiInitDevice(1,1,0,0) &amp;lt;/code&amp;gt; to initalize SPI channel 1 on the PIC. &lt;br /&gt;
&lt;br /&gt;
To initialize the nrf24L01+ chip itself, you have to options. You can either use &amp;lt;code&amp;gt; nrf24L01_initialize(..) &amp;lt;/code&amp;gt; which gives  you the opportunity to manually define every register in the chip right from the start. However, this function has 21 arguments, so it is not the most convenient to use if you don&amp;#039;t have to. Instead, you can use &amp;lt;code&amp;gt; nrf24L01_initialize_debug(bool rx, int width, bool auto_ack_on) &amp;lt;/code&amp;gt;, which gives you the option to specify whether or not the chip is a receiver or transmitter, what the payload width is, and whether or not to enable auto-acknowledge. However, it limits you to Pipe 0, an air data rate of 2 Mpbs, and RF Channel 2. However, these limitations can be adjusted easily after initialization using additional functions (see the library for all available functions). So, for example, to initialize your chip as a transmitter with a payload width of one byte and no auto-acknowledgement, you could call &amp;lt;code&amp;gt; nrf24L01_initialize_debug(0,1,0)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If you wish to display information to the screen or receive information from the keyboard, you will have to initialize the RS232 connection as well. This can be done with the following code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
int	pbClk = SYSTEMConfigPerformance(SYS_FREQ);&lt;br /&gt;
initUART2(pbClk);&lt;br /&gt;
&lt;br /&gt;
 void initUART2(int pbClk) {&lt;br /&gt;
  	 #define config1 	UART_EN | UART_IDLE_CON | UART_RX_TX | UART_DIS_WAKE | UART_DIS_LOOPBACK | UART_DIS_ABAUD | UART_NO_PAR_8BIT | UART_1STOPBIT | UART_IRDA_DIS | UART_DIS_BCLK_CTS_RTS| UART_NORMAL_RX | UART_BRGH_SIXTEEN&lt;br /&gt;
  	 #define config2		UART_TX_PIN_LOW | UART_RX_ENABLE | UART_TX_ENABLE | UART_INT_TX | UART_INT_RX_CHAR | UART_ADR_DETECT_DIS | UART_RX_OVERRUN_CLEAR	&lt;br /&gt;
   	 OpenUART2( config1, config2, pbClk/16/DESIRED_BAUDRATE-1);	// calculate actual BAUD generate value.&lt;br /&gt;
   	 ConfigIntUART2(UART_INT_PR2 | UART_RX_INT_EN);&lt;br /&gt;
   	 //INTEnableSystemMultiVectoredInt();&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Transmitter Code===&lt;br /&gt;
&lt;br /&gt;
Wirelessly transmitting data requires three steps:&lt;br /&gt;
&lt;br /&gt;
*initialize nrf24L01+ as transmitter&lt;br /&gt;
*transmit packet&lt;br /&gt;
*wait for payload to be sent&lt;br /&gt;
&lt;br /&gt;
A basic outline for such a procedure would look like:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
char data = &amp;#039;x&amp;#039;; //data to send&lt;br /&gt;
int width = 1; //width of payload&lt;br /&gt;
&lt;br /&gt;
nrf24l01_initialize_debug(false, width, false); //initialize the 24L01 to the debug configuration as TX, 1  data byte, and auto-ack disabled&lt;br /&gt;
&lt;br /&gt;
nrf24l01_write_tx_payload(&amp;amp;data, width, true); //add char to Tx queue, and transmit immediately  (char * data, int width, bool transmit_now)&lt;br /&gt;
&lt;br /&gt;
while(!(nrf24l01_irq_pin_active() &amp;amp;&amp;amp; nrf24l01_irq_tx_ds_active())); //wait until IRQ status tells us that it is done transmitting&lt;br /&gt;
&lt;br /&gt;
nrf24l01_irq_clear_all(); //clear all interrupts in the 24L01&lt;br /&gt;
&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A fully functional [[media:nrf-tx.c|transmitter c-file]] is available. It is intended to work with the receiving code file, available below, and allows for a variable payload.&lt;br /&gt;
&lt;br /&gt;
===Receiver Code===&lt;br /&gt;
Similarly, receiving data from a wireless link requires three steps:&lt;br /&gt;
*initialize nrf24L01+ as receiver&lt;br /&gt;
*wait for incoming packet&lt;br /&gt;
*write packet to memory&lt;br /&gt;
&lt;br /&gt;
That would look like: &lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
char data; //variable to recieve incoming data&lt;br /&gt;
int width = 1; //width of payload&lt;br /&gt;
&lt;br /&gt;
nrf24l01_initialize_debug(true, width, false); //initialize the 24L01 to the debug configuration as RX, 1  data byte, and auto-ack disabled&lt;br /&gt;
&lt;br /&gt;
while(!(nrf24l01_irq_pin_active() &amp;amp;&amp;amp; nrf24l01_irq_rx_dr_active())); //wait to receive a packet&lt;br /&gt;
&lt;br /&gt;
nrf24l01_read_rx_payload(&amp;amp;data, width); //get the payload into data&lt;br /&gt;
&lt;br /&gt;
nrf24l01_irq_clear_all(); //clear interrupts&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A fully functional [[media:nrf-rx.c|receiver c-file]] is available. It is intended to work with the transmitter code file, available above, and allows for a variable payload.&lt;br /&gt;
&lt;br /&gt;
===Handling Multi-byte Payloads===&lt;br /&gt;
Transmitting and receiving payloads of widths larger than one byte are handled the same exact way as described as above, except that instead of having a a single char data variable, you would have an array of chars as your data variable. Then rather then pass in the memory of address of &amp;lt;code&amp;gt;data &amp;lt;/code&amp;gt; you can simply pass in &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt; itself,  because in C, the variable representing an array is synonymous with the memory address of its first element. Examples of this are available in the attached C files.&lt;br /&gt;
&lt;br /&gt;
===Bidirectional Communication===&lt;br /&gt;
While technically the nrf24l01+ chip can only be in one mode (transmitting/receiving) at a given instant, with some clever programming you can still get a bidirectional link established between two chips. The [[media:nrf-bidirectional.c| full code for bidirectional communication]] is available on this page. Basically, the chip sits in receiver mode, listening for any incoming packets. If it receives one, it displays it to the screen. However, there in the event that a key is pressed on the local terminal, the PIC switches the mode from receiving to transmitting, transmits the data received locally, and then goes back to receiver mode.   It is not a perfect system because if a packet reaches a chip while the chip is in the middle of transmitting a packet itself, it will not pick up the packet in the air. However, the chance of this sort of situation happening would be rare, depending on the application of the system. &lt;br /&gt;
&lt;br /&gt;
To establish a bidirectional link, both PICs should have the same bidirectional c-file loaded (but this is not necessary: e.g. one PIC could only be able to transmit, and it would still be a viable one-way link ). If the on air data rate is set to 1 Mbps, then this bidirectional c-file is compatible with the [http://www.sparkfun.com/commerce/product_info.php?products_id=9019 Nordic USB Serial Converter] (note that the Nordic USB-Serial converter is only compatible with a payload width of four bytes). The payload width of the bidirectional link can be adjusted with the &amp;quot;[&amp;quot; and &amp;quot;]&amp;quot; keys, exactly as with the above code.&lt;br /&gt;
&lt;br /&gt;
==Data Rates==&lt;br /&gt;
&lt;br /&gt;
Basic timed tests were done to find out how long it took to transmit and receive different sized payloads. These tests were done by sending a packet wirelessly, then timing how long it took to get it back. A pin was raised to high while waiting and then dropped when it was received. These periods were then measured on an oscilloscope, and then averaged. The times used were only those that had 100% return rate. However, the accuracy of these packets was not checked beyond the built in CRC error-checking within the packets themselves. The rates here are to go send out a transmission and then receive it back, so the rate should be doubled for only transmitting in one direction.&lt;br /&gt;
[[Image:bps-nrf24l01.jpg|center]]&lt;/div&gt;</summary>
		<author><name>AndrewKessler</name></author>
	</entry>
	<entry>
		<id>https://hades.mech.northwestern.edu//index.php?title=PIC32MX:_High-speed_Wireless_Communication&amp;diff=19004</id>
		<title>PIC32MX: High-speed Wireless Communication</title>
		<link rel="alternate" type="text/html" href="https://hades.mech.northwestern.edu//index.php?title=PIC32MX:_High-speed_Wireless_Communication&amp;diff=19004"/>
		<updated>2010-08-26T21:37:00Z</updated>

		<summary type="html">&lt;p&gt;AndrewKessler: /* Initialization Functions */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Overview ==&lt;br /&gt;
&lt;br /&gt;
[[Image:nrf-pic1.jpg|thumb|nrf24L01+ wireless chip with pins attatched]]&lt;br /&gt;
This wiki describes how to wire a [http://www.sparkfun.com/commerce/product_info.php?products_id=691 nRF24L01+ chip] (&amp;quot;wireless chip&amp;quot;) to a PIC32 board and includes annotated code describing the functions that facilitate the transmitting and receiving of wireless data. A  [[media:Wireless-ppt.pdf|PowerPoint presentation]] covering much of the introductory information available on this page is also available. &lt;br /&gt;
&lt;br /&gt;
To operate the system, you must properly connect the wireless chips to the PIC32s, load the transmitter code onto the PIC that you wish to act as a transmitter, load the receiver code onto the PIC that you wish to act as a receiver, properly connect an RS232 cable to the PIC and open a serial communication program (e.g. HyperTerminal or [http://chiark.greenend.org.uk/~sgtatham/putty/download.html putty]), and turn the NU32 boards on. If you use the c-files provided on this pages (and everything else is set up properly), the transmitting PIC will broadcast  any characters received from the PC via RS232, and the receiving PIC will display what it receives from wireless link on the PC via RS232. The payload width can be adjusted using the &amp;quot;[&amp;quot; and &amp;quot;]&amp;quot; keys on both the transmitting and receiving PICs. Both wireless chips must be set to the same payload width in order to communicate. Payload widths may vary from 1 to 32. The transmitting PIC will not transmit until enough characters have been entered to fill a payload. Once enough characters have been entered into the transmitting PIC, the serial display will move to a new line to signal transmission.&lt;br /&gt;
&lt;br /&gt;
==Chip Basics==&lt;br /&gt;
The nrf24L01+ Module is a breakout of the nrf24L01+ 2.4 GHz transceiver, with an on board antenna. In order to get a wireless link up and running, the following parameters must be consistent between a transmitter and receiver chip:&lt;br /&gt;
&lt;br /&gt;
===Channels===&lt;br /&gt;
The channel of the nrf24L01+ chip is the frequency that it broadcasts and receives data from. The channel can range from 2.4 GHz to 2.525 GHz, at intervals no more than 1 MHz. The exact distance between channels is dependent on the on air data rate. Two wireless chips must be tuned to the same channel in order to communicate.  See the Air Data Rate section for necessary channel spacing.&lt;br /&gt;
&lt;br /&gt;
===Air Data Rate===&lt;br /&gt;
The air data rate is the rate at which the chip transmits bits wirelessly (and the rate at which it looks for them). The nrf24L01+ chip has three selectable data rates: 250 kbps, 1 Mbps, and 2 Mbps. Faster data rates draw less current, but require a greater distance between channels. Slower data rates give you the option of more channels and better receiver sensitivity, for the obvious trade off of speed. Data rates of 250 kbps and 1 Mbps require channel spacing of at least 1 MHz (allowing for 125 unique channels), and a data rate of 2 Mbps requires spacing of 2 MHz between channels (allowing for 62 channels).  Two wireless chips will not be able to communicate if they are not set to the same on air data rate.&lt;br /&gt;
&lt;br /&gt;
===Payload Width===&lt;br /&gt;
The payload is the actual data you are trying to send over a wireless link, and the payload width is how many bytes are contained within each payload. The nfr24L01+ is capable of supporting payloads up to 32 bytes. A transmitter and receiver must be set to the same payload in order to communicate. Transmission speeds for different sizes payloads are analyzed below. &lt;br /&gt;
&lt;br /&gt;
===Addresses &amp;amp; Pipes===&lt;br /&gt;
Every wireless transmission is preceded by the address of the intended receiver. The nrf24L01+ chip has 6 different receiving pipes, which means it may act as 6 receivers with 6 different addresses. Addresses may be three, four, or five bytes long. The addresses for pipe 0 and 1 may be completely different, but the addresses for pipes 2, 3, and 4 may only differ from the address of pipe 1 by their least significant byte. All active pipes feed into the same 3-packet-deep  incoming transmission queue.  Each pipe may also be set to a expect a different payload width.&lt;br /&gt;
&lt;br /&gt;
== Circuit ==&lt;br /&gt;
&lt;br /&gt;
[[Image:Wireless-circuit.jpg|thumb|Schematic of the nRF24L01+ connected to the PIC32_NU32 board]]&lt;br /&gt;
&lt;br /&gt;
The wireless chip has 8 pins that need to be wired to the PIC (all I/O are relative to PIC):&lt;br /&gt;
&lt;br /&gt;
*Vcc: +3.3 Vdc supply&amp;lt;br&amp;gt;&lt;br /&gt;
*CE:  uC pin C1 (input)&amp;lt;br&amp;gt;&lt;br /&gt;
*CSN: uC pin C2 (output) &amp;lt;br&amp;gt;&lt;br /&gt;
*SCK: uC pin D10, configured as SCK(SPI) (output)&amp;lt;br&amp;gt;&lt;br /&gt;
*MOSI: uC pin D0, configured as SDO(SPI) (output) &amp;lt;br&amp;gt;&lt;br /&gt;
*MISO: uC pin C4, configured as SDI(SPI) (input)&amp;lt;br&amp;gt;&lt;br /&gt;
*IRQ: uC pin B0 (input) &amp;lt;br&amp;gt;&lt;br /&gt;
*GND: common digital ground&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The +3.3V and ground are provided by the NU32 board. The term &amp;quot;uC&amp;quot; above stands for microcontroller, which is the PIC32 in our case. &lt;br /&gt;
&lt;br /&gt;
Descriptions of the wireless chip&amp;#039;s pins can be found in Brennan Ball&amp;#039;s DIYembedded [http://www.diyembedded.com/tutorials/nrf24l01_0/nrf24l01_tutorial_0.pdf Tutorial 0]. The SCK, MOSI, and MISO pins interface with the SPI on the PIC32 which allows for communication between the PIC and the wireless chip. The GPIO pins will be initialized as digital inputs or outputs in the code to enable/disable the wireless chip and check the wireless data transfer/receive stats.&lt;br /&gt;
&lt;br /&gt;
In order to print information from the PIC to the PC, we need to wire an [[PIC_RS232]] cable&amp;#039;s transfer and receive lines to the UART ports of the NU32 board (F4, F5).&lt;br /&gt;
&lt;br /&gt;
==Code==&lt;br /&gt;
&lt;br /&gt;
===Driver===&lt;br /&gt;
Besides the main C files for the transmitter and receiver, the project also needs the [[media:Wireless-files.zip|nRF24L01.h header file and C file]]. These driver files were created by Brennan Ball, and are explained in detail in his [http://blog.diyembedded.com/ tutorials]. The following things must be changed in the header file available on his website to make it compatible with the NU32 board:&lt;br /&gt;
*pin registers and masks must be set to the appropriate values&lt;br /&gt;
*the &amp;quot;HardwareProfile.h&amp;quot; NU32 specific file must be included &lt;br /&gt;
&lt;br /&gt;
These changes are accounted for the the driver available on this page. All of the SPI functions trace back to a single function to send and read a single byte, which must be defined in the main c file. &lt;br /&gt;
&lt;br /&gt;
This function is available here: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 unsigned char spi_send_read_byte(unsigned char byte) {&lt;br /&gt;
  	 unsigned short	txData, rxData; // transmit, receive characters&lt;br /&gt;
   	 int chn = 1; // SPI channel to use (1 or 2)&lt;br /&gt;
  	 &lt;br /&gt;
   	 txData = byte; // take inputted byte and store into txData   &lt;br /&gt;
   	 SpiChnPutC(chn, txData);			// send data&lt;br /&gt;
 	 rxData = SpiChnGetC(chn);			// retreive over channel chn the received data into rxData&lt;br /&gt;
    &lt;br /&gt;
  	 return rxData; &lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
===Initialization Functions===&lt;br /&gt;
In order to get a wireless link up and running, you will need to initialize both the wireless chip and SPI communication on the PIC. &lt;br /&gt;
To intialize SPI on the PIC, create the following function in your main C file:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;oid SpiInitDevice(int chn, int isMaster, int frmEn, int frmMaster) {&lt;br /&gt;
   	 unsigned int config = SPI_CON_MODE8|SPI_CON_SMP|SPI_CON_ON;	// SPI configuration word&lt;br /&gt;
   	 if(isMaster)&lt;br /&gt;
   	 {&lt;br /&gt;
   		 config|=SPI_CON_MSTEN;&lt;br /&gt;
   	 }&lt;br /&gt;
   	 if(frmEn)&lt;br /&gt;
   	 {&lt;br /&gt;
   		 config|=SPI_CON_FRMEN;&lt;br /&gt;
   		 if(!frmMaster) {   &lt;br /&gt;
   			 config|=SPI_CON_FRMSYNC;&lt;br /&gt;
      	 }&lt;br /&gt;
   	 }&lt;br /&gt;
  	 SpiChnOpen(chn, config, 4);	// divide fpb by 4, configure the I/O ports. Not using SS in this example&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
You can then call this function with the call &amp;lt;code&amp;gt; SpiInitDevice(1,1,0,0) &amp;lt;/code&amp;gt; to initalize SPI channel 1 on the PIC. &lt;br /&gt;
&lt;br /&gt;
To initialize the nrf24L01+ chip itself, you have to options. You can either use &amp;lt;code&amp;gt; nrf24L01_initialize(..) &amp;lt;/code&amp;gt; which gives  you the opportunity to manually define every register in the chip right from the start. However, this function has 21 arguments, so it is not the most convenient to use if you don&amp;#039;t have to. Instead, you can use &amp;lt;code&amp;gt; nrf24L01_initialize_debug(bool rx, int width, bool auto_ack_on) &amp;lt;/code&amp;gt;, which gives you the option to specify whether or not the chip is a receiver or transmitter, what the payload width is, and whether or not to enable auto-acknowledge. However, it limits you to Pipe 0, an air data rate of 2 Mpbs, and RF Channel 2. However, these limitations can be adjusted easily after initialization using additional functions (see the library for all available functions). So, for example, to initialize your chip as a transmitter with a payload width of one byte and no auto-acknowledgement, you could call &amp;lt;code&amp;gt; nrf24L01_initialize_debug(0,1,0)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If you wish to display information to the screen or receive information from the keyboard, you will have to initialize the RS232 connection as well. This can be done with the following code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
int	pbClk = SYSTEMConfigPerformance(SYS_FREQ);&lt;br /&gt;
initUART2(pbClk);&lt;br /&gt;
&lt;br /&gt;
 void initUART2(int pbClk) {&lt;br /&gt;
  	 #define config1 	UART_EN | UART_IDLE_CON | UART_RX_TX | UART_DIS_WAKE | UART_DIS_LOOPBACK | UART_DIS_ABAUD | UART_NO_PAR_8BIT | UART_1STOPBIT | UART_IRDA_DIS | UART_DIS_BCLK_CTS_RTS| UART_NORMAL_RX | UART_BRGH_SIXTEEN&lt;br /&gt;
  	 #define config2		UART_TX_PIN_LOW | UART_RX_ENABLE | UART_TX_ENABLE | UART_INT_TX | UART_INT_RX_CHAR | UART_ADR_DETECT_DIS | UART_RX_OVERRUN_CLEAR	&lt;br /&gt;
   	 OpenUART2( config1, config2, pbClk/16/DESIRED_BAUDRATE-1);	// calculate actual BAUD generate value.&lt;br /&gt;
   	 ConfigIntUART2(UART_INT_PR2 | UART_RX_INT_EN);&lt;br /&gt;
   	 //INTEnableSystemMultiVectoredInt();&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Transmitter Code===&lt;br /&gt;
&lt;br /&gt;
Wirelessly transmitting data requires three steps:&lt;br /&gt;
&lt;br /&gt;
*initialize nrf24L01+ as transmitter&lt;br /&gt;
*transmit packet&lt;br /&gt;
*wait for payload to be sent&lt;br /&gt;
&lt;br /&gt;
A basic outline for such a procedure would look like:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;lt;code&amp;gt;&lt;br /&gt;
char data = &amp;#039;x&amp;#039;; //data to send&lt;br /&gt;
int width = 1; //width of payload&lt;br /&gt;
&lt;br /&gt;
nrf24l01_initialize_debug(false, width, false); //initialize the 24L01 to the debug configuration as TX, 1  data byte, and auto-ack disabled&lt;br /&gt;
&lt;br /&gt;
nrf24l01_write_tx_payload(&amp;amp;data, width, true); //add char to Tx queue, and transmit immediately  (char * data, int width, bool transmit_now)&lt;br /&gt;
&lt;br /&gt;
while(!(nrf24l01_irq_pin_active() &amp;amp;&amp;amp; nrf24l01_irq_tx_ds_active())); //wait until IRQ status tells us that it is done transmitting&lt;br /&gt;
&lt;br /&gt;
nrf24l01_irq_clear_all(); //clear all interrupts in the 24L01&lt;br /&gt;
&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A fully functional [[media:nrf-tx.c|transmitter c-file]] is available. It is intended to work with the receiving code file, available below, and allows for a variable payload.&lt;br /&gt;
&lt;br /&gt;
===Receiver Code===&lt;br /&gt;
Similarly, receiving data from a wireless link requires three steps:&lt;br /&gt;
*initialize nrf24L01+ as receiver&lt;br /&gt;
*wait for incoming packet&lt;br /&gt;
*write packet to memory&lt;br /&gt;
&lt;br /&gt;
That would look like: &lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
char data; //variable to recieve incoming data&lt;br /&gt;
int width = 1; //width of payload&lt;br /&gt;
&lt;br /&gt;
nrf24l01_initialize_debug(true, width, false); //initialize the 24L01 to the debug configuration as RX, 1  data byte, and auto-ack disabled&lt;br /&gt;
&lt;br /&gt;
while(!(nrf24l01_irq_pin_active() &amp;amp;&amp;amp; nrf24l01_irq_rx_dr_active())); //wait to receive a packet&lt;br /&gt;
&lt;br /&gt;
nrf24l01_read_rx_payload(&amp;amp;data, width); //get the payload into data&lt;br /&gt;
&lt;br /&gt;
nrf24l01_irq_clear_all(); //clear interrupts&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A fully functional [[media:nrf-rx.c|receiver c-file]] is available. It is intended to work with the transmitter code file, available above, and allows for a variable payload.&lt;br /&gt;
&lt;br /&gt;
===Handling Multi-byte Payloads===&lt;br /&gt;
Transmitting and receiving payloads of widths larger than one byte are handled the same exact way as described as above, except that instead of having a a single char data variable, you would have an array of chars as your data variable. Then rather then pass in the memory of address of &amp;lt;code&amp;gt;data &amp;lt;/code&amp;gt; you can simply pass in &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt; itself,  because in C, the variable representing an array is synonymous with the memory address of its first element. Examples of this are available in the attached C files.&lt;br /&gt;
&lt;br /&gt;
===Bidirectional Communication===&lt;br /&gt;
While technically the nrf24l01+ chip can only be in one mode (transmitting/receiving) at a given instant, with some clever programming you can still get a bidirectional link established between two chips. The [[media:nrf-bidirectional.c| full code for bidirectional communication]] is available on this page. Basically, the chip sits in receiver mode, listening for any incoming packets. If it receives one, it displays it to the screen. However, there in the event that a key is pressed on the local terminal, the PIC switches the mode from receiving to transmitting, transmits the data received locally, and then goes back to receiver mode.   It is not a perfect system because if a packet reaches a chip while the chip is in the middle of transmitting a packet itself, it will not pick up the packet in the air. However, the chance of this sort of situation happening would be rare, depending on the application of the system. &lt;br /&gt;
&lt;br /&gt;
To establish a bidirectional link, both PICs should have the same bidirectional c-file loaded (but this is not necessary: e.g. one PIC could only be able to transmit, and it would still be a viable one-way link ). If the on air data rate is set to 1 Mbps, then this bidirectional c-file is compatible with the [http://www.sparkfun.com/commerce/product_info.php?products_id=9019 Nordic USB Serial Converter] (note that the Nordic USB-Serial converter is only compatible with a payload width of four bytes). The payload width of the bidirectional link can be adjusted with the &amp;quot;[&amp;quot; and &amp;quot;]&amp;quot; keys, exactly as with the above code.&lt;br /&gt;
&lt;br /&gt;
==Data Rates==&lt;br /&gt;
&lt;br /&gt;
Basic timed tests were done to find out how long it took to transmit and receive different sized payloads. These tests were done by sending a packet wirelessly, then timing how long it took to get it back. A pin was raised to high while waiting and then dropped when it was received. These periods were then measured on an oscilloscope, and then averaged. The times used were only those that had 100% return rate. However, the accuracy of these packets was not checked beyond the built in CRC error-checking within the packets themselves. The rates here are to go send out a transmission and then receive it back, so the rate should be doubled for only transmitting in one direction.&lt;br /&gt;
[[Image:bps-nrf24l01.jpg|center]]&lt;/div&gt;</summary>
		<author><name>AndrewKessler</name></author>
	</entry>
	<entry>
		<id>https://hades.mech.northwestern.edu//index.php?title=PIC32MX:_High-speed_Wireless_Communication&amp;diff=19003</id>
		<title>PIC32MX: High-speed Wireless Communication</title>
		<link rel="alternate" type="text/html" href="https://hades.mech.northwestern.edu//index.php?title=PIC32MX:_High-speed_Wireless_Communication&amp;diff=19003"/>
		<updated>2010-08-26T21:35:51Z</updated>

		<summary type="html">&lt;p&gt;AndrewKessler: /* Transmitter Code */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Overview ==&lt;br /&gt;
&lt;br /&gt;
[[Image:nrf-pic1.jpg|thumb|nrf24L01+ wireless chip with pins attatched]]&lt;br /&gt;
This wiki describes how to wire a [http://www.sparkfun.com/commerce/product_info.php?products_id=691 nRF24L01+ chip] (&amp;quot;wireless chip&amp;quot;) to a PIC32 board and includes annotated code describing the functions that facilitate the transmitting and receiving of wireless data. A  [[media:Wireless-ppt.pdf|PowerPoint presentation]] covering much of the introductory information available on this page is also available. &lt;br /&gt;
&lt;br /&gt;
To operate the system, you must properly connect the wireless chips to the PIC32s, load the transmitter code onto the PIC that you wish to act as a transmitter, load the receiver code onto the PIC that you wish to act as a receiver, properly connect an RS232 cable to the PIC and open a serial communication program (e.g. HyperTerminal or [http://chiark.greenend.org.uk/~sgtatham/putty/download.html putty]), and turn the NU32 boards on. If you use the c-files provided on this pages (and everything else is set up properly), the transmitting PIC will broadcast  any characters received from the PC via RS232, and the receiving PIC will display what it receives from wireless link on the PC via RS232. The payload width can be adjusted using the &amp;quot;[&amp;quot; and &amp;quot;]&amp;quot; keys on both the transmitting and receiving PICs. Both wireless chips must be set to the same payload width in order to communicate. Payload widths may vary from 1 to 32. The transmitting PIC will not transmit until enough characters have been entered to fill a payload. Once enough characters have been entered into the transmitting PIC, the serial display will move to a new line to signal transmission.&lt;br /&gt;
&lt;br /&gt;
==Chip Basics==&lt;br /&gt;
The nrf24L01+ Module is a breakout of the nrf24L01+ 2.4 GHz transceiver, with an on board antenna. In order to get a wireless link up and running, the following parameters must be consistent between a transmitter and receiver chip:&lt;br /&gt;
&lt;br /&gt;
===Channels===&lt;br /&gt;
The channel of the nrf24L01+ chip is the frequency that it broadcasts and receives data from. The channel can range from 2.4 GHz to 2.525 GHz, at intervals no more than 1 MHz. The exact distance between channels is dependent on the on air data rate. Two wireless chips must be tuned to the same channel in order to communicate.  See the Air Data Rate section for necessary channel spacing.&lt;br /&gt;
&lt;br /&gt;
===Air Data Rate===&lt;br /&gt;
The air data rate is the rate at which the chip transmits bits wirelessly (and the rate at which it looks for them). The nrf24L01+ chip has three selectable data rates: 250 kbps, 1 Mbps, and 2 Mbps. Faster data rates draw less current, but require a greater distance between channels. Slower data rates give you the option of more channels and better receiver sensitivity, for the obvious trade off of speed. Data rates of 250 kbps and 1 Mbps require channel spacing of at least 1 MHz (allowing for 125 unique channels), and a data rate of 2 Mbps requires spacing of 2 MHz between channels (allowing for 62 channels).  Two wireless chips will not be able to communicate if they are not set to the same on air data rate.&lt;br /&gt;
&lt;br /&gt;
===Payload Width===&lt;br /&gt;
The payload is the actual data you are trying to send over a wireless link, and the payload width is how many bytes are contained within each payload. The nfr24L01+ is capable of supporting payloads up to 32 bytes. A transmitter and receiver must be set to the same payload in order to communicate. Transmission speeds for different sizes payloads are analyzed below. &lt;br /&gt;
&lt;br /&gt;
===Addresses &amp;amp; Pipes===&lt;br /&gt;
Every wireless transmission is preceded by the address of the intended receiver. The nrf24L01+ chip has 6 different receiving pipes, which means it may act as 6 receivers with 6 different addresses. Addresses may be three, four, or five bytes long. The addresses for pipe 0 and 1 may be completely different, but the addresses for pipes 2, 3, and 4 may only differ from the address of pipe 1 by their least significant byte. All active pipes feed into the same 3-packet-deep  incoming transmission queue.  Each pipe may also be set to a expect a different payload width.&lt;br /&gt;
&lt;br /&gt;
== Circuit ==&lt;br /&gt;
&lt;br /&gt;
[[Image:Wireless-circuit.jpg|thumb|Schematic of the nRF24L01+ connected to the PIC32_NU32 board]]&lt;br /&gt;
&lt;br /&gt;
The wireless chip has 8 pins that need to be wired to the PIC (all I/O are relative to PIC):&lt;br /&gt;
&lt;br /&gt;
*Vcc: +3.3 Vdc supply&amp;lt;br&amp;gt;&lt;br /&gt;
*CE:  uC pin C1 (input)&amp;lt;br&amp;gt;&lt;br /&gt;
*CSN: uC pin C2 (output) &amp;lt;br&amp;gt;&lt;br /&gt;
*SCK: uC pin D10, configured as SCK(SPI) (output)&amp;lt;br&amp;gt;&lt;br /&gt;
*MOSI: uC pin D0, configured as SDO(SPI) (output) &amp;lt;br&amp;gt;&lt;br /&gt;
*MISO: uC pin C4, configured as SDI(SPI) (input)&amp;lt;br&amp;gt;&lt;br /&gt;
*IRQ: uC pin B0 (input) &amp;lt;br&amp;gt;&lt;br /&gt;
*GND: common digital ground&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The +3.3V and ground are provided by the NU32 board. The term &amp;quot;uC&amp;quot; above stands for microcontroller, which is the PIC32 in our case. &lt;br /&gt;
&lt;br /&gt;
Descriptions of the wireless chip&amp;#039;s pins can be found in Brennan Ball&amp;#039;s DIYembedded [http://www.diyembedded.com/tutorials/nrf24l01_0/nrf24l01_tutorial_0.pdf Tutorial 0]. The SCK, MOSI, and MISO pins interface with the SPI on the PIC32 which allows for communication between the PIC and the wireless chip. The GPIO pins will be initialized as digital inputs or outputs in the code to enable/disable the wireless chip and check the wireless data transfer/receive stats.&lt;br /&gt;
&lt;br /&gt;
In order to print information from the PIC to the PC, we need to wire an [[PIC_RS232]] cable&amp;#039;s transfer and receive lines to the UART ports of the NU32 board (F4, F5).&lt;br /&gt;
&lt;br /&gt;
==Code==&lt;br /&gt;
&lt;br /&gt;
===Driver===&lt;br /&gt;
Besides the main C files for the transmitter and receiver, the project also needs the [[media:Wireless-files.zip|nRF24L01.h header file and C file]]. These driver files were created by Brennan Ball, and are explained in detail in his [http://blog.diyembedded.com/ tutorials]. The following things must be changed in the header file available on his website to make it compatible with the NU32 board:&lt;br /&gt;
*pin registers and masks must be set to the appropriate values&lt;br /&gt;
*the &amp;quot;HardwareProfile.h&amp;quot; NU32 specific file must be included &lt;br /&gt;
&lt;br /&gt;
These changes are accounted for the the driver available on this page. All of the SPI functions trace back to a single function to send and read a single byte, which must be defined in the main c file. &lt;br /&gt;
&lt;br /&gt;
This function is available here: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 unsigned char spi_send_read_byte(unsigned char byte) {&lt;br /&gt;
  	 unsigned short	txData, rxData; // transmit, receive characters&lt;br /&gt;
   	 int chn = 1; // SPI channel to use (1 or 2)&lt;br /&gt;
  	 &lt;br /&gt;
   	 txData = byte; // take inputted byte and store into txData   &lt;br /&gt;
   	 SpiChnPutC(chn, txData);			// send data&lt;br /&gt;
 	 rxData = SpiChnGetC(chn);			// retreive over channel chn the received data into rxData&lt;br /&gt;
    &lt;br /&gt;
  	 return rxData; &lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
===Initialization Functions===&lt;br /&gt;
In order to get a wireless link up and running, you will need to initialize both the wireless chip and SPI communication on the PIC. &lt;br /&gt;
To intialize SPI on the PIC, create the following function in your main C file:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;oid SpiInitDevice(int chn, int isMaster, int frmEn, int frmMaster) {&lt;br /&gt;
   	 unsigned int config = SPI_CON_MODE8|SPI_CON_SMP|SPI_CON_ON;	// SPI configuration word&lt;br /&gt;
   	 if(isMaster)&lt;br /&gt;
   	 {&lt;br /&gt;
   		 config|=SPI_CON_MSTEN;&lt;br /&gt;
   	 }&lt;br /&gt;
   	 if(frmEn)&lt;br /&gt;
   	 {&lt;br /&gt;
   		 config|=SPI_CON_FRMEN;&lt;br /&gt;
   		 if(!frmMaster) {   &lt;br /&gt;
   			 config|=SPI_CON_FRMSYNC;&lt;br /&gt;
      	 }&lt;br /&gt;
   	 }&lt;br /&gt;
  	 SpiChnOpen(chn, config, 4);	// divide fpb by 4, configure the I/O ports. Not using SS in this example&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
You can then call this function with the call &amp;lt;code&amp;gt; SpiInitDevice(1,1,0,0) &amp;lt;/code&amp;gt; to initalize SPI channel 1 on the PIC. &lt;br /&gt;
&lt;br /&gt;
To initialize the nrf24L01+ chip itself, you have to options. You can either use &amp;lt;code&amp;gt; nrf24L01_initialize(..) &amp;lt;/code&amp;gt; which gives  you the opportunity to manually define every register in the chip right from the start. However, this function has 21 arguments, so it is not the most convenient to use if you don&amp;#039;t have to. Instead, you can use &amp;lt;code&amp;gt; nrf24L01_initialize_debug(bool rx, int width, bool auto_ack_on) &amp;lt;/code&amp;gt;, which gives you the option to specify whether or not the chip is a receiver or transmitter, what the payload width is, and whether or not to enable auto-acknowledge. However, it limits you to Pipe 0, an air data rate of 2 Mpbs, and RF Channel 2. However, these limitations can be adjusted easily after initialization using additional functions (see the library for all available functions). So, for example, to initialize your chip as a transmitter with a payload width of one byte and no auto-acknowledgement, you could call &amp;lt;code&amp;gt; nrf24L01_initialize_debug(0,1,0)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If you wish to display information to the screen or receive information from the keyboard, you will have to initialize the RS232 connection as well. This can be done with the following code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;lt;code&amp;gt;&lt;br /&gt;
int	pbClk = SYSTEMConfigPerformance(SYS_FREQ);&lt;br /&gt;
initUART2(pbClk);&lt;br /&gt;
&lt;br /&gt;
 void initUART2(int pbClk) {&lt;br /&gt;
  	 #define config1 	UART_EN | UART_IDLE_CON | UART_RX_TX | UART_DIS_WAKE | UART_DIS_LOOPBACK | UART_DIS_ABAUD | UART_NO_PAR_8BIT | UART_1STOPBIT | UART_IRDA_DIS | UART_DIS_BCLK_CTS_RTS| UART_NORMAL_RX | UART_BRGH_SIXTEEN&lt;br /&gt;
  	 #define config2		UART_TX_PIN_LOW | UART_RX_ENABLE | UART_TX_ENABLE | UART_INT_TX | UART_INT_RX_CHAR | UART_ADR_DETECT_DIS | UART_RX_OVERRUN_CLEAR	&lt;br /&gt;
   	 OpenUART2( config1, config2, pbClk/16/DESIRED_BAUDRATE-1);	// calculate actual BAUD generate value.&lt;br /&gt;
   	 ConfigIntUART2(UART_INT_PR2 | UART_RX_INT_EN);&lt;br /&gt;
   	 //INTEnableSystemMultiVectoredInt();&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Transmitter Code===&lt;br /&gt;
&lt;br /&gt;
Wirelessly transmitting data requires three steps:&lt;br /&gt;
&lt;br /&gt;
*initialize nrf24L01+ as transmitter&lt;br /&gt;
*transmit packet&lt;br /&gt;
*wait for payload to be sent&lt;br /&gt;
&lt;br /&gt;
A basic outline for such a procedure would look like:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;lt;code&amp;gt;&lt;br /&gt;
char data = &amp;#039;x&amp;#039;; //data to send&lt;br /&gt;
int width = 1; //width of payload&lt;br /&gt;
&lt;br /&gt;
nrf24l01_initialize_debug(false, width, false); //initialize the 24L01 to the debug configuration as TX, 1  data byte, and auto-ack disabled&lt;br /&gt;
&lt;br /&gt;
nrf24l01_write_tx_payload(&amp;amp;data, width, true); //add char to Tx queue, and transmit immediately  (char * data, int width, bool transmit_now)&lt;br /&gt;
&lt;br /&gt;
while(!(nrf24l01_irq_pin_active() &amp;amp;&amp;amp; nrf24l01_irq_tx_ds_active())); //wait until IRQ status tells us that it is done transmitting&lt;br /&gt;
&lt;br /&gt;
nrf24l01_irq_clear_all(); //clear all interrupts in the 24L01&lt;br /&gt;
&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A fully functional [[media:nrf-tx.c|transmitter c-file]] is available. It is intended to work with the receiving code file, available below, and allows for a variable payload.&lt;br /&gt;
&lt;br /&gt;
===Receiver Code===&lt;br /&gt;
Similarly, receiving data from a wireless link requires three steps:&lt;br /&gt;
*initialize nrf24L01+ as receiver&lt;br /&gt;
*wait for incoming packet&lt;br /&gt;
*write packet to memory&lt;br /&gt;
&lt;br /&gt;
That would look like: &lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
char data; //variable to recieve incoming data&lt;br /&gt;
int width = 1; //width of payload&lt;br /&gt;
&lt;br /&gt;
nrf24l01_initialize_debug(true, width, false); //initialize the 24L01 to the debug configuration as RX, 1  data byte, and auto-ack disabled&lt;br /&gt;
&lt;br /&gt;
while(!(nrf24l01_irq_pin_active() &amp;amp;&amp;amp; nrf24l01_irq_rx_dr_active())); //wait to receive a packet&lt;br /&gt;
&lt;br /&gt;
nrf24l01_read_rx_payload(&amp;amp;data, width); //get the payload into data&lt;br /&gt;
&lt;br /&gt;
nrf24l01_irq_clear_all(); //clear interrupts&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A fully functional [[media:nrf-rx.c|receiver c-file]] is available. It is intended to work with the transmitter code file, available above, and allows for a variable payload.&lt;br /&gt;
&lt;br /&gt;
===Handling Multi-byte Payloads===&lt;br /&gt;
Transmitting and receiving payloads of widths larger than one byte are handled the same exact way as described as above, except that instead of having a a single char data variable, you would have an array of chars as your data variable. Then rather then pass in the memory of address of &amp;lt;code&amp;gt;data &amp;lt;/code&amp;gt; you can simply pass in &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt; itself,  because in C, the variable representing an array is synonymous with the memory address of its first element. Examples of this are available in the attached C files.&lt;br /&gt;
&lt;br /&gt;
===Bidirectional Communication===&lt;br /&gt;
While technically the nrf24l01+ chip can only be in one mode (transmitting/receiving) at a given instant, with some clever programming you can still get a bidirectional link established between two chips. The [[media:nrf-bidirectional.c| full code for bidirectional communication]] is available on this page. Basically, the chip sits in receiver mode, listening for any incoming packets. If it receives one, it displays it to the screen. However, there in the event that a key is pressed on the local terminal, the PIC switches the mode from receiving to transmitting, transmits the data received locally, and then goes back to receiver mode.   It is not a perfect system because if a packet reaches a chip while the chip is in the middle of transmitting a packet itself, it will not pick up the packet in the air. However, the chance of this sort of situation happening would be rare, depending on the application of the system. &lt;br /&gt;
&lt;br /&gt;
To establish a bidirectional link, both PICs should have the same bidirectional c-file loaded (but this is not necessary: e.g. one PIC could only be able to transmit, and it would still be a viable one-way link ). If the on air data rate is set to 1 Mbps, then this bidirectional c-file is compatible with the [http://www.sparkfun.com/commerce/product_info.php?products_id=9019 Nordic USB Serial Converter] (note that the Nordic USB-Serial converter is only compatible with a payload width of four bytes). The payload width of the bidirectional link can be adjusted with the &amp;quot;[&amp;quot; and &amp;quot;]&amp;quot; keys, exactly as with the above code.&lt;br /&gt;
&lt;br /&gt;
==Data Rates==&lt;br /&gt;
&lt;br /&gt;
Basic timed tests were done to find out how long it took to transmit and receive different sized payloads. These tests were done by sending a packet wirelessly, then timing how long it took to get it back. A pin was raised to high while waiting and then dropped when it was received. These periods were then measured on an oscilloscope, and then averaged. The times used were only those that had 100% return rate. However, the accuracy of these packets was not checked beyond the built in CRC error-checking within the packets themselves. The rates here are to go send out a transmission and then receive it back, so the rate should be doubled for only transmitting in one direction.&lt;br /&gt;
[[Image:bps-nrf24l01.jpg|center]]&lt;/div&gt;</summary>
		<author><name>AndrewKessler</name></author>
	</entry>
	<entry>
		<id>https://hades.mech.northwestern.edu//index.php?title=PIC32MX:_High-speed_Wireless_Communication&amp;diff=19002</id>
		<title>PIC32MX: High-speed Wireless Communication</title>
		<link rel="alternate" type="text/html" href="https://hades.mech.northwestern.edu//index.php?title=PIC32MX:_High-speed_Wireless_Communication&amp;diff=19002"/>
		<updated>2010-08-26T21:35:28Z</updated>

		<summary type="html">&lt;p&gt;AndrewKessler: /* Initialization Functions */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Overview ==&lt;br /&gt;
&lt;br /&gt;
[[Image:nrf-pic1.jpg|thumb|nrf24L01+ wireless chip with pins attatched]]&lt;br /&gt;
This wiki describes how to wire a [http://www.sparkfun.com/commerce/product_info.php?products_id=691 nRF24L01+ chip] (&amp;quot;wireless chip&amp;quot;) to a PIC32 board and includes annotated code describing the functions that facilitate the transmitting and receiving of wireless data. A  [[media:Wireless-ppt.pdf|PowerPoint presentation]] covering much of the introductory information available on this page is also available. &lt;br /&gt;
&lt;br /&gt;
To operate the system, you must properly connect the wireless chips to the PIC32s, load the transmitter code onto the PIC that you wish to act as a transmitter, load the receiver code onto the PIC that you wish to act as a receiver, properly connect an RS232 cable to the PIC and open a serial communication program (e.g. HyperTerminal or [http://chiark.greenend.org.uk/~sgtatham/putty/download.html putty]), and turn the NU32 boards on. If you use the c-files provided on this pages (and everything else is set up properly), the transmitting PIC will broadcast  any characters received from the PC via RS232, and the receiving PIC will display what it receives from wireless link on the PC via RS232. The payload width can be adjusted using the &amp;quot;[&amp;quot; and &amp;quot;]&amp;quot; keys on both the transmitting and receiving PICs. Both wireless chips must be set to the same payload width in order to communicate. Payload widths may vary from 1 to 32. The transmitting PIC will not transmit until enough characters have been entered to fill a payload. Once enough characters have been entered into the transmitting PIC, the serial display will move to a new line to signal transmission.&lt;br /&gt;
&lt;br /&gt;
==Chip Basics==&lt;br /&gt;
The nrf24L01+ Module is a breakout of the nrf24L01+ 2.4 GHz transceiver, with an on board antenna. In order to get a wireless link up and running, the following parameters must be consistent between a transmitter and receiver chip:&lt;br /&gt;
&lt;br /&gt;
===Channels===&lt;br /&gt;
The channel of the nrf24L01+ chip is the frequency that it broadcasts and receives data from. The channel can range from 2.4 GHz to 2.525 GHz, at intervals no more than 1 MHz. The exact distance between channels is dependent on the on air data rate. Two wireless chips must be tuned to the same channel in order to communicate.  See the Air Data Rate section for necessary channel spacing.&lt;br /&gt;
&lt;br /&gt;
===Air Data Rate===&lt;br /&gt;
The air data rate is the rate at which the chip transmits bits wirelessly (and the rate at which it looks for them). The nrf24L01+ chip has three selectable data rates: 250 kbps, 1 Mbps, and 2 Mbps. Faster data rates draw less current, but require a greater distance between channels. Slower data rates give you the option of more channels and better receiver sensitivity, for the obvious trade off of speed. Data rates of 250 kbps and 1 Mbps require channel spacing of at least 1 MHz (allowing for 125 unique channels), and a data rate of 2 Mbps requires spacing of 2 MHz between channels (allowing for 62 channels).  Two wireless chips will not be able to communicate if they are not set to the same on air data rate.&lt;br /&gt;
&lt;br /&gt;
===Payload Width===&lt;br /&gt;
The payload is the actual data you are trying to send over a wireless link, and the payload width is how many bytes are contained within each payload. The nfr24L01+ is capable of supporting payloads up to 32 bytes. A transmitter and receiver must be set to the same payload in order to communicate. Transmission speeds for different sizes payloads are analyzed below. &lt;br /&gt;
&lt;br /&gt;
===Addresses &amp;amp; Pipes===&lt;br /&gt;
Every wireless transmission is preceded by the address of the intended receiver. The nrf24L01+ chip has 6 different receiving pipes, which means it may act as 6 receivers with 6 different addresses. Addresses may be three, four, or five bytes long. The addresses for pipe 0 and 1 may be completely different, but the addresses for pipes 2, 3, and 4 may only differ from the address of pipe 1 by their least significant byte. All active pipes feed into the same 3-packet-deep  incoming transmission queue.  Each pipe may also be set to a expect a different payload width.&lt;br /&gt;
&lt;br /&gt;
== Circuit ==&lt;br /&gt;
&lt;br /&gt;
[[Image:Wireless-circuit.jpg|thumb|Schematic of the nRF24L01+ connected to the PIC32_NU32 board]]&lt;br /&gt;
&lt;br /&gt;
The wireless chip has 8 pins that need to be wired to the PIC (all I/O are relative to PIC):&lt;br /&gt;
&lt;br /&gt;
*Vcc: +3.3 Vdc supply&amp;lt;br&amp;gt;&lt;br /&gt;
*CE:  uC pin C1 (input)&amp;lt;br&amp;gt;&lt;br /&gt;
*CSN: uC pin C2 (output) &amp;lt;br&amp;gt;&lt;br /&gt;
*SCK: uC pin D10, configured as SCK(SPI) (output)&amp;lt;br&amp;gt;&lt;br /&gt;
*MOSI: uC pin D0, configured as SDO(SPI) (output) &amp;lt;br&amp;gt;&lt;br /&gt;
*MISO: uC pin C4, configured as SDI(SPI) (input)&amp;lt;br&amp;gt;&lt;br /&gt;
*IRQ: uC pin B0 (input) &amp;lt;br&amp;gt;&lt;br /&gt;
*GND: common digital ground&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The +3.3V and ground are provided by the NU32 board. The term &amp;quot;uC&amp;quot; above stands for microcontroller, which is the PIC32 in our case. &lt;br /&gt;
&lt;br /&gt;
Descriptions of the wireless chip&amp;#039;s pins can be found in Brennan Ball&amp;#039;s DIYembedded [http://www.diyembedded.com/tutorials/nrf24l01_0/nrf24l01_tutorial_0.pdf Tutorial 0]. The SCK, MOSI, and MISO pins interface with the SPI on the PIC32 which allows for communication between the PIC and the wireless chip. The GPIO pins will be initialized as digital inputs or outputs in the code to enable/disable the wireless chip and check the wireless data transfer/receive stats.&lt;br /&gt;
&lt;br /&gt;
In order to print information from the PIC to the PC, we need to wire an [[PIC_RS232]] cable&amp;#039;s transfer and receive lines to the UART ports of the NU32 board (F4, F5).&lt;br /&gt;
&lt;br /&gt;
==Code==&lt;br /&gt;
&lt;br /&gt;
===Driver===&lt;br /&gt;
Besides the main C files for the transmitter and receiver, the project also needs the [[media:Wireless-files.zip|nRF24L01.h header file and C file]]. These driver files were created by Brennan Ball, and are explained in detail in his [http://blog.diyembedded.com/ tutorials]. The following things must be changed in the header file available on his website to make it compatible with the NU32 board:&lt;br /&gt;
*pin registers and masks must be set to the appropriate values&lt;br /&gt;
*the &amp;quot;HardwareProfile.h&amp;quot; NU32 specific file must be included &lt;br /&gt;
&lt;br /&gt;
These changes are accounted for the the driver available on this page. All of the SPI functions trace back to a single function to send and read a single byte, which must be defined in the main c file. &lt;br /&gt;
&lt;br /&gt;
This function is available here: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 unsigned char spi_send_read_byte(unsigned char byte) {&lt;br /&gt;
  	 unsigned short	txData, rxData; // transmit, receive characters&lt;br /&gt;
   	 int chn = 1; // SPI channel to use (1 or 2)&lt;br /&gt;
  	 &lt;br /&gt;
   	 txData = byte; // take inputted byte and store into txData   &lt;br /&gt;
   	 SpiChnPutC(chn, txData);			// send data&lt;br /&gt;
 	 rxData = SpiChnGetC(chn);			// retreive over channel chn the received data into rxData&lt;br /&gt;
    &lt;br /&gt;
  	 return rxData; &lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
===Initialization Functions===&lt;br /&gt;
In order to get a wireless link up and running, you will need to initialize both the wireless chip and SPI communication on the PIC. &lt;br /&gt;
To intialize SPI on the PIC, create the following function in your main C file:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;oid SpiInitDevice(int chn, int isMaster, int frmEn, int frmMaster) {&lt;br /&gt;
   	 unsigned int config = SPI_CON_MODE8|SPI_CON_SMP|SPI_CON_ON;	// SPI configuration word&lt;br /&gt;
   	 if(isMaster)&lt;br /&gt;
   	 {&lt;br /&gt;
   		 config|=SPI_CON_MSTEN;&lt;br /&gt;
   	 }&lt;br /&gt;
   	 if(frmEn)&lt;br /&gt;
   	 {&lt;br /&gt;
   		 config|=SPI_CON_FRMEN;&lt;br /&gt;
   		 if(!frmMaster) {   &lt;br /&gt;
   			 config|=SPI_CON_FRMSYNC;&lt;br /&gt;
      	 }&lt;br /&gt;
   	 }&lt;br /&gt;
  	 SpiChnOpen(chn, config, 4);	// divide fpb by 4, configure the I/O ports. Not using SS in this example&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
You can then call this function with the call &amp;lt;code&amp;gt; SpiInitDevice(1,1,0,0) &amp;lt;/code&amp;gt; to initalize SPI channel 1 on the PIC. &lt;br /&gt;
&lt;br /&gt;
To initialize the nrf24L01+ chip itself, you have to options. You can either use &amp;lt;code&amp;gt; nrf24L01_initialize(..) &amp;lt;/code&amp;gt; which gives  you the opportunity to manually define every register in the chip right from the start. However, this function has 21 arguments, so it is not the most convenient to use if you don&amp;#039;t have to. Instead, you can use &amp;lt;code&amp;gt; nrf24L01_initialize_debug(bool rx, int width, bool auto_ack_on) &amp;lt;/code&amp;gt;, which gives you the option to specify whether or not the chip is a receiver or transmitter, what the payload width is, and whether or not to enable auto-acknowledge. However, it limits you to Pipe 0, an air data rate of 2 Mpbs, and RF Channel 2. However, these limitations can be adjusted easily after initialization using additional functions (see the library for all available functions). So, for example, to initialize your chip as a transmitter with a payload width of one byte and no auto-acknowledgement, you could call &amp;lt;code&amp;gt; nrf24L01_initialize_debug(0,1,0)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If you wish to display information to the screen or receive information from the keyboard, you will have to initialize the RS232 connection as well. This can be done with the following code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;lt;code&amp;gt;&lt;br /&gt;
int	pbClk = SYSTEMConfigPerformance(SYS_FREQ);&lt;br /&gt;
initUART2(pbClk);&lt;br /&gt;
&lt;br /&gt;
 void initUART2(int pbClk) {&lt;br /&gt;
  	 #define config1 	UART_EN | UART_IDLE_CON | UART_RX_TX | UART_DIS_WAKE | UART_DIS_LOOPBACK | UART_DIS_ABAUD | UART_NO_PAR_8BIT | UART_1STOPBIT | UART_IRDA_DIS | UART_DIS_BCLK_CTS_RTS| UART_NORMAL_RX | UART_BRGH_SIXTEEN&lt;br /&gt;
  	 #define config2		UART_TX_PIN_LOW | UART_RX_ENABLE | UART_TX_ENABLE | UART_INT_TX | UART_INT_RX_CHAR | UART_ADR_DETECT_DIS | UART_RX_OVERRUN_CLEAR	&lt;br /&gt;
   	 OpenUART2( config1, config2, pbClk/16/DESIRED_BAUDRATE-1);	// calculate actual BAUD generate value.&lt;br /&gt;
   	 ConfigIntUART2(UART_INT_PR2 | UART_RX_INT_EN);&lt;br /&gt;
   	 //INTEnableSystemMultiVectoredInt();&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Transmitter Code===&lt;br /&gt;
&lt;br /&gt;
Wirelessly transmitting data requires three steps:&lt;br /&gt;
&lt;br /&gt;
*initialize nrf24L01+ as transmitter&lt;br /&gt;
*transmit packet&lt;br /&gt;
*wait for payload to be sent&lt;br /&gt;
&lt;br /&gt;
A basic outline for such a procedure would look like:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
char data = &amp;#039;x&amp;#039;; //data to send&lt;br /&gt;
int width = 1; //width of payload&lt;br /&gt;
&lt;br /&gt;
nrf24l01_initialize_debug(false, width, false); //initialize the 24L01 to the debug configuration as TX, 1  data byte, and auto-ack disabled&lt;br /&gt;
&lt;br /&gt;
nrf24l01_write_tx_payload(&amp;amp;data, width, true); //add char to Tx queue, and transmit immediately  (char * data, int width, bool transmit_now)&lt;br /&gt;
&lt;br /&gt;
while(!(nrf24l01_irq_pin_active() &amp;amp;&amp;amp; nrf24l01_irq_tx_ds_active())); //wait until IRQ status tells us that it is done transmitting&lt;br /&gt;
&lt;br /&gt;
nrf24l01_irq_clear_all(); //clear all interrupts in the 24L01&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A fully functional [[media:nrf-tx.c|transmitter c-file]] is available. It is intended to work with the receiving code file, available below, and allows for a variable payload. &lt;br /&gt;
 &lt;br /&gt;
===Receiver Code===&lt;br /&gt;
Similarly, receiving data from a wireless link requires three steps:&lt;br /&gt;
*initialize nrf24L01+ as receiver&lt;br /&gt;
*wait for incoming packet&lt;br /&gt;
*write packet to memory&lt;br /&gt;
&lt;br /&gt;
That would look like: &lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
char data; //variable to recieve incoming data&lt;br /&gt;
int width = 1; //width of payload&lt;br /&gt;
&lt;br /&gt;
nrf24l01_initialize_debug(true, width, false); //initialize the 24L01 to the debug configuration as RX, 1  data byte, and auto-ack disabled&lt;br /&gt;
&lt;br /&gt;
while(!(nrf24l01_irq_pin_active() &amp;amp;&amp;amp; nrf24l01_irq_rx_dr_active())); //wait to receive a packet&lt;br /&gt;
&lt;br /&gt;
nrf24l01_read_rx_payload(&amp;amp;data, width); //get the payload into data&lt;br /&gt;
&lt;br /&gt;
nrf24l01_irq_clear_all(); //clear interrupts&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A fully functional [[media:nrf-rx.c|receiver c-file]] is available. It is intended to work with the transmitter code file, available above, and allows for a variable payload.&lt;br /&gt;
&lt;br /&gt;
===Handling Multi-byte Payloads===&lt;br /&gt;
Transmitting and receiving payloads of widths larger than one byte are handled the same exact way as described as above, except that instead of having a a single char data variable, you would have an array of chars as your data variable. Then rather then pass in the memory of address of &amp;lt;code&amp;gt;data &amp;lt;/code&amp;gt; you can simply pass in &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt; itself,  because in C, the variable representing an array is synonymous with the memory address of its first element. Examples of this are available in the attached C files.&lt;br /&gt;
&lt;br /&gt;
===Bidirectional Communication===&lt;br /&gt;
While technically the nrf24l01+ chip can only be in one mode (transmitting/receiving) at a given instant, with some clever programming you can still get a bidirectional link established between two chips. The [[media:nrf-bidirectional.c| full code for bidirectional communication]] is available on this page. Basically, the chip sits in receiver mode, listening for any incoming packets. If it receives one, it displays it to the screen. However, there in the event that a key is pressed on the local terminal, the PIC switches the mode from receiving to transmitting, transmits the data received locally, and then goes back to receiver mode.   It is not a perfect system because if a packet reaches a chip while the chip is in the middle of transmitting a packet itself, it will not pick up the packet in the air. However, the chance of this sort of situation happening would be rare, depending on the application of the system. &lt;br /&gt;
&lt;br /&gt;
To establish a bidirectional link, both PICs should have the same bidirectional c-file loaded (but this is not necessary: e.g. one PIC could only be able to transmit, and it would still be a viable one-way link ). If the on air data rate is set to 1 Mbps, then this bidirectional c-file is compatible with the [http://www.sparkfun.com/commerce/product_info.php?products_id=9019 Nordic USB Serial Converter] (note that the Nordic USB-Serial converter is only compatible with a payload width of four bytes). The payload width of the bidirectional link can be adjusted with the &amp;quot;[&amp;quot; and &amp;quot;]&amp;quot; keys, exactly as with the above code.&lt;br /&gt;
&lt;br /&gt;
==Data Rates==&lt;br /&gt;
&lt;br /&gt;
Basic timed tests were done to find out how long it took to transmit and receive different sized payloads. These tests were done by sending a packet wirelessly, then timing how long it took to get it back. A pin was raised to high while waiting and then dropped when it was received. These periods were then measured on an oscilloscope, and then averaged. The times used were only those that had 100% return rate. However, the accuracy of these packets was not checked beyond the built in CRC error-checking within the packets themselves. The rates here are to go send out a transmission and then receive it back, so the rate should be doubled for only transmitting in one direction.&lt;br /&gt;
[[Image:bps-nrf24l01.jpg|center]]&lt;/div&gt;</summary>
		<author><name>AndrewKessler</name></author>
	</entry>
	<entry>
		<id>https://hades.mech.northwestern.edu//index.php?title=File:Nrf-bidirectional.c&amp;diff=19001</id>
		<title>File:Nrf-bidirectional.c</title>
		<link rel="alternate" type="text/html" href="https://hades.mech.northwestern.edu//index.php?title=File:Nrf-bidirectional.c&amp;diff=19001"/>
		<updated>2010-08-24T19:41:32Z</updated>

		<summary type="html">&lt;p&gt;AndrewKessler: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>AndrewKessler</name></author>
	</entry>
	<entry>
		<id>https://hades.mech.northwestern.edu//index.php?title=PIC32MX:_High-speed_Wireless_Communication&amp;diff=19000</id>
		<title>PIC32MX: High-speed Wireless Communication</title>
		<link rel="alternate" type="text/html" href="https://hades.mech.northwestern.edu//index.php?title=PIC32MX:_High-speed_Wireless_Communication&amp;diff=19000"/>
		<updated>2010-08-24T17:44:46Z</updated>

		<summary type="html">&lt;p&gt;AndrewKessler: /* Bidirectional Communication */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Overview ==&lt;br /&gt;
&lt;br /&gt;
[[Image:nrf-pic1.jpg|thumb|nrf24L01+ wireless chip with pins attatched]]&lt;br /&gt;
This wiki describes how to wire a [http://www.sparkfun.com/commerce/product_info.php?products_id=691 nRF24L01+ chip] (&amp;quot;wireless chip&amp;quot;) to a PIC32 board and includes annotated code describing the functions that facilitate the transmitting and receiving of wireless data. A  [[media:Wireless-ppt.pdf|PowerPoint presentation]] covering much of the introductory information available on this page is also available. &lt;br /&gt;
&lt;br /&gt;
To operate the system, you must properly connect the wireless chips to the PIC32s, load the transmitter code onto the PIC that you wish to act as a transmitter, load the receiver code onto the PIC that you wish to act as a receiver, properly connect an RS232 cable to the PIC and open a serial communication program (e.g. HyperTerminal or [http://chiark.greenend.org.uk/~sgtatham/putty/download.html putty]), and turn the NU32 boards on. If you use the c-files provided on this pages (and everything else is set up properly), the transmitting PIC will broadcast  any characters received from the PC via RS232, and the receiving PIC will display what it receives from wireless link on the PC via RS232. The payload width can be adjusted using the &amp;quot;[&amp;quot; and &amp;quot;]&amp;quot; keys on both the transmitting and receiving PICs. Both wireless chips must be set to the same payload width in order to communicate. Payload widths may vary from 1 to 32. The transmitting PIC will not transmit until enough characters have been entered to fill a payload. Once enough characters have been entered into the transmitting PIC, the serial display will move to a new line to signal transmission.&lt;br /&gt;
&lt;br /&gt;
==Chip Basics==&lt;br /&gt;
The nrf24L01+ Module is a breakout of the nrf24L01+ 2.4 GHz transceiver, with an on board antenna. In order to get a wireless link up and running, the following parameters must be consistent between a transmitter and receiver chip:&lt;br /&gt;
&lt;br /&gt;
===Channels===&lt;br /&gt;
The channel of the nrf24L01+ chip is the frequency that it broadcasts and receives data from. The channel can range from 2.4 GHz to 2.525 GHz, at intervals no more than 1 MHz. The exact distance between channels is dependent on the on air data rate. Two wireless chips must be tuned to the same channel in order to communicate.  See the Air Data Rate section for necessary channel spacing.&lt;br /&gt;
&lt;br /&gt;
===Air Data Rate===&lt;br /&gt;
The air data rate is the rate at which the chip transmits bits wirelessly (and the rate at which it looks for them). The nrf24L01+ chip has three selectable data rates: 250 kbps, 1 Mbps, and 2 Mbps. Faster data rates draw less current, but require a greater distance between channels. Slower data rates give you the option of more channels and better receiver sensitivity, for the obvious trade off of speed. Data rates of 250 kbps and 1 Mbps require channel spacing of at least 1 MHz (allowing for 125 unique channels), and a data rate of 2 Mbps requires spacing of 2 MHz between channels (allowing for 62 channels).  Two wireless chips will not be able to communicate if they are not set to the same on air data rate.&lt;br /&gt;
&lt;br /&gt;
===Payload Width===&lt;br /&gt;
The payload is the actual data you are trying to send over a wireless link, and the payload width is how many bytes are contained within each payload. The nfr24L01+ is capable of supporting payloads up to 32 bytes. A transmitter and receiver must be set to the same payload in order to communicate. Transmission speeds for different sizes payloads are analyzed below. &lt;br /&gt;
&lt;br /&gt;
===Addresses &amp;amp; Pipes===&lt;br /&gt;
Every wireless transmission is preceded by the address of the intended receiver. The nrf24L01+ chip has 6 different receiving pipes, which means it may act as 6 receivers with 6 different addresses. Addresses may be three, four, or five bytes long. The addresses for pipe 0 and 1 may be completely different, but the addresses for pipes 2, 3, and 4 may only differ from the address of pipe 1 by their least significant byte. All active pipes feed into the same 3-packet-deep  incoming transmission queue.  Each pipe may also be set to a expect a different payload width.&lt;br /&gt;
&lt;br /&gt;
== Circuit ==&lt;br /&gt;
&lt;br /&gt;
[[Image:Wireless-circuit.jpg|thumb|Schematic of the nRF24L01+ connected to the PIC32_NU32 board]]&lt;br /&gt;
&lt;br /&gt;
The wireless chip has 8 pins that need to be wired to the PIC (all I/O are relative to PIC):&lt;br /&gt;
&lt;br /&gt;
*Vcc: +3.3 Vdc supply&amp;lt;br&amp;gt;&lt;br /&gt;
*CE:  uC pin C1 (input)&amp;lt;br&amp;gt;&lt;br /&gt;
*CSN: uC pin C2 (output) &amp;lt;br&amp;gt;&lt;br /&gt;
*SCK: uC pin D10, configured as SCK(SPI) (output)&amp;lt;br&amp;gt;&lt;br /&gt;
*MOSI: uC pin D0, configured as SDO(SPI) (output) &amp;lt;br&amp;gt;&lt;br /&gt;
*MISO: uC pin C4, configured as SDI(SPI) (input)&amp;lt;br&amp;gt;&lt;br /&gt;
*IRQ: uC pin B0 (input) &amp;lt;br&amp;gt;&lt;br /&gt;
*GND: common digital ground&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The +3.3V and ground are provided by the NU32 board. The term &amp;quot;uC&amp;quot; above stands for microcontroller, which is the PIC32 in our case. &lt;br /&gt;
&lt;br /&gt;
Descriptions of the wireless chip&amp;#039;s pins can be found in Brennan Ball&amp;#039;s DIYembedded [http://www.diyembedded.com/tutorials/nrf24l01_0/nrf24l01_tutorial_0.pdf Tutorial 0]. The SCK, MOSI, and MISO pins interface with the SPI on the PIC32 which allows for communication between the PIC and the wireless chip. The GPIO pins will be initialized as digital inputs or outputs in the code to enable/disable the wireless chip and check the wireless data transfer/receive stats.&lt;br /&gt;
&lt;br /&gt;
In order to print information from the PIC to the PC, we need to wire an [[PIC_RS232]] cable&amp;#039;s transfer and receive lines to the UART ports of the NU32 board (F4, F5).&lt;br /&gt;
&lt;br /&gt;
==Code==&lt;br /&gt;
&lt;br /&gt;
===Driver===&lt;br /&gt;
Besides the main C files for the transmitter and receiver, the project also needs the [[media:Wireless-files.zip|nRF24L01.h header file and C file]]. These driver files were created by Brennan Ball, and are explained in detail in his [http://blog.diyembedded.com/ tutorials]. The following things must be changed in the header file available on his website to make it compatible with the NU32 board:&lt;br /&gt;
*pin registers and masks must be set to the appropriate values&lt;br /&gt;
*the &amp;quot;HardwareProfile.h&amp;quot; NU32 specific file must be included &lt;br /&gt;
&lt;br /&gt;
These changes are accounted for the the driver available on this page. All of the SPI functions trace back to a single function to send and read a single byte, which must be defined in the main c file. &lt;br /&gt;
&lt;br /&gt;
This function is available here: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 unsigned char spi_send_read_byte(unsigned char byte) {&lt;br /&gt;
  	 unsigned short	txData, rxData; // transmit, receive characters&lt;br /&gt;
   	 int chn = 1; // SPI channel to use (1 or 2)&lt;br /&gt;
  	 &lt;br /&gt;
   	 txData = byte; // take inputted byte and store into txData   &lt;br /&gt;
   	 SpiChnPutC(chn, txData);			// send data&lt;br /&gt;
 	 rxData = SpiChnGetC(chn);			// retreive over channel chn the received data into rxData&lt;br /&gt;
    &lt;br /&gt;
  	 return rxData; &lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
===Initialization Functions===&lt;br /&gt;
In order to get a wireless link up and running, you will need to initialize both the wireless chip and SPI communication on the PIC. &lt;br /&gt;
To intialize SPI on the PIC, create the following function in your main C file:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;oid SpiInitDevice(int chn, int isMaster, int frmEn, int frmMaster) {&lt;br /&gt;
   	 unsigned int config = SPI_CON_MODE8|SPI_CON_SMP|SPI_CON_ON;	// SPI configuration word&lt;br /&gt;
   	 if(isMaster)&lt;br /&gt;
   	 {&lt;br /&gt;
   		 config|=SPI_CON_MSTEN;&lt;br /&gt;
   	 }&lt;br /&gt;
   	 if(frmEn)&lt;br /&gt;
   	 {&lt;br /&gt;
   		 config|=SPI_CON_FRMEN;&lt;br /&gt;
   		 if(!frmMaster) {   &lt;br /&gt;
   			 config|=SPI_CON_FRMSYNC;&lt;br /&gt;
      	 }&lt;br /&gt;
   	 }&lt;br /&gt;
  	 SpiChnOpen(chn, config, 4);	// divide fpb by 4, configure the I/O ports. Not using SS in this example&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
You can then call this function with the call &amp;lt;code&amp;gt; SpiInitDevice(1,1,0,0) &amp;lt;/code&amp;gt; to initalize SPI channel 1 on the PIC. &lt;br /&gt;
&lt;br /&gt;
To initialize the nrf24L01+ chip itself, you have to options. You can either use &amp;lt;code&amp;gt; nrf24L01_initialize(..) &amp;lt;/code&amp;gt; which gives  you the opportunity to manually define every register in the chip right from the start. However, this function has 21 arguments, so it is not the most convenient to use if you don&amp;#039;t have to. Instead, you can use &amp;lt;code&amp;gt; nrf24L01_initialize_debug(bool rx, int width, bool auto_ack_on) &amp;lt;/code&amp;gt;, which gives you the option to specify whether or not the chip is a receiver or transmitter, what the payload width is, and whether or not to enable auto-acknowledge. However, it limits you to Pipe 0, an air data rate of 2 Mpbs, and RF Channel 2. However, these limitations can be adjusted easily after initialization using additional functions (see the library for all available functions). So, for example, to initialize your chip as a transmitter with a payload width of one byte and no auto-acknowledgement, you could call &amp;lt;code&amp;gt; nrf24L01_initialize_debug(0,1,0)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Transmitter Code===&lt;br /&gt;
&lt;br /&gt;
Wirelessly transmitting data requires three steps:&lt;br /&gt;
&lt;br /&gt;
*initialize nrf24L01+ as transmitter&lt;br /&gt;
*transmit packet&lt;br /&gt;
*wait for payload to be sent&lt;br /&gt;
&lt;br /&gt;
A basic outline for such a procedure would look like:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
char data = &amp;#039;x&amp;#039;; //data to send&lt;br /&gt;
int width = 1; //width of payload&lt;br /&gt;
&lt;br /&gt;
nrf24l01_initialize_debug(false, width, false); //initialize the 24L01 to the debug configuration as TX, 1  data byte, and auto-ack disabled&lt;br /&gt;
&lt;br /&gt;
nrf24l01_write_tx_payload(&amp;amp;data, width, true); //add char to Tx queue, and transmit immediately  (char * data, int width, bool transmit_now)&lt;br /&gt;
&lt;br /&gt;
while(!(nrf24l01_irq_pin_active() &amp;amp;&amp;amp; nrf24l01_irq_tx_ds_active())); //wait until IRQ status tells us that it is done transmitting&lt;br /&gt;
&lt;br /&gt;
nrf24l01_irq_clear_all(); //clear all interrupts in the 24L01&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A fully functional [[media:nrf-tx.c|transmitter c-file]] is available. It is intended to work with the receiving code file, available below, and allows for a variable payload. &lt;br /&gt;
 &lt;br /&gt;
===Receiver Code===&lt;br /&gt;
Similarly, receiving data from a wireless link requires three steps:&lt;br /&gt;
*initialize nrf24L01+ as receiver&lt;br /&gt;
*wait for incoming packet&lt;br /&gt;
*write packet to memory&lt;br /&gt;
&lt;br /&gt;
That would look like: &lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
char data; //variable to recieve incoming data&lt;br /&gt;
int width = 1; //width of payload&lt;br /&gt;
&lt;br /&gt;
nrf24l01_initialize_debug(true, width, false); //initialize the 24L01 to the debug configuration as RX, 1  data byte, and auto-ack disabled&lt;br /&gt;
&lt;br /&gt;
while(!(nrf24l01_irq_pin_active() &amp;amp;&amp;amp; nrf24l01_irq_rx_dr_active())); //wait to receive a packet&lt;br /&gt;
&lt;br /&gt;
nrf24l01_read_rx_payload(&amp;amp;data, width); //get the payload into data&lt;br /&gt;
&lt;br /&gt;
nrf24l01_irq_clear_all(); //clear interrupts&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A fully functional [[media:nrf-rx.c|receiver c-file]] is available. It is intended to work with the transmitter code file, available above, and allows for a variable payload.&lt;br /&gt;
&lt;br /&gt;
===Handling Multi-byte Payloads===&lt;br /&gt;
Transmitting and receiving payloads of widths larger than one byte are handled the same exact way as described as above, except that instead of having a a single char data variable, you would have an array of chars as your data variable. Then rather then pass in the memory of address of &amp;lt;code&amp;gt;data &amp;lt;/code&amp;gt; you can simply pass in &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt; itself,  because in C, the variable representing an array is synonymous with the memory address of its first element. Examples of this are available in the attached C files.&lt;br /&gt;
&lt;br /&gt;
===Bidirectional Communication===&lt;br /&gt;
While technically the nrf24l01+ chip can only be in one mode (transmitting/receiving) at a given instant, with some clever programming you can still get a bidirectional link established between two chips. The [[media:nrf-bidirectional.c| full code for bidirectional communication]] is available on this page. Basically, the chip sits in receiver mode, listening for any incoming packets. If it receives one, it displays it to the screen. However, there in the event that a key is pressed on the local terminal, the PIC switches the mode from receiving to transmitting, transmits the data received locally, and then goes back to receiver mode.   It is not a perfect system because if a packet reaches a chip while the chip is in the middle of transmitting a packet itself, it will not pick up the packet in the air. However, the chance of this sort of situation happening would be rare, depending on the application of the system. &lt;br /&gt;
&lt;br /&gt;
To establish a bidirectional link, both PICs should have the same bidirectional c-file loaded (but this is not necessary: e.g. one PIC could only be able to transmit, and it would still be a viable one-way link ). If the on air data rate is set to 1 Mbps, then this bidirectional c-file is compatible with the [http://www.sparkfun.com/commerce/product_info.php?products_id=9019 Nordic USB Serial Converter] (note that the Nordic USB-Serial converter is only compatible with a payload width of four bytes). The payload width of the bidirectional link can be adjusted with the &amp;quot;[&amp;quot; and &amp;quot;]&amp;quot; keys, exactly as with the above code.&lt;br /&gt;
&lt;br /&gt;
==Data Rates==&lt;br /&gt;
&lt;br /&gt;
Basic timed tests were done to find out how long it took to transmit and receive different sized payloads. These tests were done by sending a packet wirelessly, then timing how long it took to get it back. A pin was raised to high while waiting and then dropped when it was received. These periods were then measured on an oscilloscope, and then averaged. The times used were only those that had 100% return rate. However, the accuracy of these packets was not checked beyond the built in CRC error-checking within the packets themselves. The rates here are to go send out a transmission and then receive it back, so the rate should be doubled for only transmitting in one direction.&lt;br /&gt;
[[Image:bps-nrf24l01.jpg|center]]&lt;/div&gt;</summary>
		<author><name>AndrewKessler</name></author>
	</entry>
</feed>