Difference between revisions of "PIC32MX: High-speed Wireless Communication"

From Mech
Jump to navigationJump to search
Line 38: Line 38:
== Code ==
== Code ==


/* **************************************************************
/* **************************************************************

WirelessTransmitter.c
WirelessTransmitter.c
Lab 5: High-speed Wireless Communication
Lab 5: High-speed Wireless Communication
Jonathan Drake, Caitlin Ramsey
Jonathan Drake, Caitlin Ramsey
2010-02-16
2010-02-16

This code initializes the nRF24L01+ chip as a transmitter and
This code initializes the nRF24L01+ chip as a transmitter and
continuously transmits a character every 100ms. The loop contains
continuously transmits a character every 100ms. The loop contains
code to both output the program's status to the PC via RS232
code to both output the program's status to the PC via RS232
cable and onboard LEDs.
cable and onboard LEDs.

************************************************************** */
************************************************************** */


// Includes
// Includes
#include "HardwareProfile.h"
#include "HardwareProfile.h"
#include "nrf24l01.h"
#include "nrf24l01.h"

// Function Declarations
// Function Declarations
// Note: Descriptions of functions found after main() function
// Note: Descriptions of functions found after main() function
void Initialize(void);
void Initialize(void);
void InitializeIO(void);
void InitializeIO(void);
void SpiInitDevice(int chn, int isMaster, int frmEn, int frmMaster);
void SpiInitDevice(int chn, int isMaster, int frmEn, int frmMaster);
void initUART2(int pbClk);
void initUART2(int pbClk);
unsigned char spi_send_read_byte(unsigned char byte);
unsigned char spi_send_read_byte(unsigned char byte);
void Delayms( unsigned t);
void Delayms( unsigned t);
void Delayus( unsigned t);
void Delayus( unsigned t);
void Delaytus( unsigned t);
void Delaytus( unsigned t);

// Constants
// Constants
#define DESIRED_BAUDRATE (19200) // The desired BaudRate for RS232 communication w/ UART
#define DESIRED_BAUDRATE (19200) // The desired BaudRate for RS232 communication w/ UART

// Main Function
// Main Function
int main(void)
int main(void)
{
Initialize(); // initialize onboard LEDs, IO pins, UART2, SPI1, set up nRF24L01+ as TX

char RS232_Out_Buffer[64]; // buffer for printing data to the screen via UART
unsigned char data = 'x'; // char to be transmitted

// print char to screen
sprintf(RS232_Out_Buffer, "data to send = %c\r\n", data);
putsUART2(RS232_Out_Buffer);

while(1)
{
{
Initialize(); // initialize onboard LEDs, IO pins, UART2, SPI1, set up nRF24L01+ as TX
putsUART2("...\r"); // print ... to show transmission
nrf24l01_irq_clear_all(); //clear all interrupts in the 24L01
char RS232_Out_Buffer[64]; // buffer for printing data to the screen via UART
nrf24l01_set_as_tx(); // force 24L01 to be a transmitter (this is a double-check)
unsigned char data = 'x'; // char to be transmitted

//transmit received char over RF, length = 1 byte, true = send away
// print char to screen
nrf24l01_write_tx_payload(&data, 1, true);
sprintf(RS232_Out_Buffer, "data to send = %c\r\n", data);
putsUART2(RS232_Out_Buffer);
// is the 24L01 activated?
if (nrf24l01_irq_pin_active()) {
mLED_1_On();
while(1)
} else {
{
putsUART2("...\r"); // print ... to show transmission
mLED_1_Off();
nrf24l01_irq_clear_all(); //clear all interrupts in the 24L01
nrf24l01_set_as_tx(); // force 24L01 to be a transmitter (this is a double-check)
//transmit received char over RF, length = 1 byte, true = send away
nrf24l01_write_tx_payload(&data, 1, true);
// is the 24L01 activated?
if (nrf24l01_irq_pin_active()) {
mLED_1_On();
} else {
mLED_1_Off();
}
// is the 24L01 an active transmitter?
if (nrf24l01_irq_tx_ds_active()) {
mLED_2_On();
} else {
mLED_2_Off();
}
// wait until the packet has been sent or the maximum number of retries has been reached
while(!(nrf24l01_irq_pin_active() && nrf24l01_irq_tx_ds_active()));
// toggle onboard LED 3 to indicate loop iterating
mLED_3_Toggle();
Delayms(100);
}
}
}
// Initialize all initialize functions (function descriptions to follow)
void Initialize(void)
{
// initialize peripheral bus clock to SYS_FREQ (80 MHz)
int pbClk;
pbClk = SYSTEMConfigPerformance(SYS_FREQ);
// initialize UART
// is the 24L01 an active transmitter?
initUART2(pbClk);
if (nrf24l01_irq_tx_ds_active()) {
mLED_2_On();
} else {
mLED_2_Off();
}
// initialize input/output pins
// wait until the packet has been sent or the maximum number of retries has been reached
InitializeIO();
while(!(nrf24l01_irq_pin_active() && nrf24l01_irq_tx_ds_active()));
// toggle onboard LED 3 to indicate loop iterating
mLED_3_Toggle();
Delayms(100);
}

}

// Initialize all initialize functions (function descriptions to follow)
void Initialize(void)
{
// initialize peripheral bus clock to SYS_FREQ (80 MHz)
int pbClk;
pbClk = SYSTEMConfigPerformance(SYS_FREQ);
// initialize UART
// initialize the SPI channel 1 as master, no frame mode
SpiInitDevice(1, 1, 0, 0);
initUART2(pbClk);
//initialize 24L01 to debug configuration as transfer, 1 byte data size, and auto-acknowledge mode disabled
nrf24l01_initialize_debug(false, 1, false);
// initialize all onboard LEDs on NU32
mInitAllLEDs();
// if program initialized correctly, indicate on PC & onboard LEDs
// initialize input/output pins
putsUART2("\r\n***** System Initialized *****\r\n");
InitializeIO();
mLED_0_On();

}
// initialize the SPI channel 1 as master, no frame mode
SpiInitDevice(1, 1, 0, 0);
// initialize IO pins
//initialize 24L01 to debug configuration as transfer, 1 byte data size, and auto-acknowledge mode disabled
void InitializeIO(void)
nrf24l01_initialize_debug(false, 1, false);
{
TRISBbits.TRISB0 = 1; // set IRQ pin as input
TRISC = 0xFFF9; // make CSN, CE digital outputs
PORTC = 0x0004; // set CSN bit active
}
// initialize all onboard LEDs on NU32
// initialize UART2
mInitAllLEDs();
void initUART2(int pbClk)

// if program initialized correctly, indicate on PC & onboard LEDs
putsUART2("\r\n***** System Initialized *****\r\n");
mLED_0_On();
}

// initialize IO pins
void InitializeIO(void)
{
TRISBbits.TRISB0 = 1; // set IRQ pin as input
TRISC = 0xFFF9; // make CSN, CE digital outputs
PORTC = 0x0004; // set CSN bit active
}


// initialize UART2
void initUART2(int pbClk)
{
#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
#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
OpenUART2( config1, config2, pbClk/16/DESIRED_BAUDRATE-1); // calculate actual BAUD generate value.
ConfigIntUART2(UART_INT_PR2 | UART_RX_INT_EN);
}


// initialize SPI
void SpiInitDevice(int chn, int isMaster, int frmEn, int frmMaster)
{
unsigned int config = SPI_CON_MODE16|SPI_CON_SMP|SPI_CON_ON; // SPI configuration word
if(isMaster)
{
{
#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
config|=SPI_CON_MSTEN;
#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
OpenUART2( config1, config2, pbClk/16/DESIRED_BAUDRATE-1); // calculate actual BAUD generate value.
ConfigIntUART2(UART_INT_PR2 | UART_RX_INT_EN);
}
}
if(frmEn)
// initialize SPI
void SpiInitDevice(int chn, int isMaster, int frmEn, int frmMaster)
{
{
unsigned int config = SPI_CON_MODE16|SPI_CON_SMP|SPI_CON_ON; // SPI configuration word
config|=SPI_CON_FRMEN;
if(!frmMaster)
if(isMaster)
{
{
config|=SPI_CON_FRMSYNC;
config|=SPI_CON_MSTEN;
}
}
if(frmEn)
{
config|=SPI_CON_FRMEN;
if(!frmMaster)
{
config|=SPI_CON_FRMSYNC;
}
}
SpiChnOpen(chn, config, 4); // divide fpb by 4, configure the I/O ports. Not using SS in this example
}
}
SpiChnOpen(chn, config, 4); // divide fpb by 4, configure the I/O ports. Not using SS in this example
}

/* ******************************************************

Function: spi_send_read_byte
Inputs: unsigned char byte
Outputs: unsigned short rxData

This function is required by the 24L01 header file.
It takes the inputted byte, sends it over the chosen
SPI channel, then waits to retreive data back.

****************************************************** */
unsigned char spi_send_read_byte(unsigned char byte)
{
unsigned short txData, rxData; // transmit, receive characters
int chn = 1; // SPI channel to use (1 or 2)
/* ******************************************************
txData = byte; // take inputted byte and store into txData
SpiChnPutC(chn, txData); // send data
Function: spi_send_read_byte
rxData = SpiChnGetC(chn); // retreive over channel chn the received data into rxData
Inputs: unsigned char byte

Outputs: unsigned short rxData
return rxData;
}
This function is required by the 24L01 header file.

It takes the inputted byte, sends it over the chosen

SPI channel, then waits to retreive data back.
/* ******************************************************

****************************************************** */
Functions: Delayms, Delayus, Delaytus
unsigned char spi_send_read_byte(unsigned char byte)
Inputs: unsigned t
{
Outputs: none
unsigned short txData, rxData; // transmit, receive characters

int chn = 1; // SPI channel to use (1 or 2)
These functions are required by the 24L01 header file.
They take an input of t (ms, us, us/10) and delay the
txData = byte; // take inputted byte and store into txData
program.
SpiChnPutC(chn, txData); // send data

rxData = SpiChnGetC(chn); // retreive over channel chn the received data into rxData
****************************************************** */
void Delayms( unsigned t)
return rxData;
// This uses Timer 1, can be changed to another timer. Assumes FPB = SYS_FREQ
{
OpenTimer1(T1_ON | T1_PS_1_256, 0xFFFF);
while (t--)
{ // t x 1ms loop
WriteTimer1(0);
while (ReadTimer1() < SYS_FREQ/256/1000);
}
}
CloseTimer1();
} // Delayms
/* ******************************************************

void Delayus( unsigned t)
Functions: Delayms, Delayus, Delaytus
{
Inputs: unsigned t
OpenTimer1(T1_ON | T1_PS_1_256, 0xFFFF);
Outputs: none
while (t--)
{ // t x 1ms loop
These functions are required by the 24L01 header file.
WriteTimer1(0);
They take an input of t (ms, us, us/10) and delay the
while (ReadTimer1() < SYS_FREQ/256/1000000);
program.
}
CloseTimer1();
****************************************************** */
}// Delayus
void Delayms( unsigned t)

// This uses Timer 1, can be changed to another timer. Assumes FPB = SYS_FREQ
void Delaytus( unsigned t)
{
{
OpenTimer1(T1_ON | T1_PS_1_256, 0xFFFF);
OpenTimer1(T1_ON | T1_PS_1_256, 0xFFFF);
while (t--)
while (t--)
{ // t x 1ms loop
{ // t x 1ms loop
WriteTimer1(0);
WriteTimer1(0);
while (ReadTimer1() < SYS_FREQ/256/10000000);
while (ReadTimer1() < SYS_FREQ/256/1000);
}
}
CloseTimer1();
CloseTimer1();
}// Delaytus
} // Delayms
void Delayus( unsigned t)
{
OpenTimer1(T1_ON | T1_PS_1_256, 0xFFFF);
while (t--)
{ // t x 1ms loop
WriteTimer1(0);
while (ReadTimer1() < SYS_FREQ/256/1000000);
}
CloseTimer1();
}// Delayus
void Delaytus( unsigned t)
{
OpenTimer1(T1_ON | T1_PS_1_256, 0xFFFF);
while (t--)
{ // t x 1ms loop
WriteTimer1(0);
while (ReadTimer1() < SYS_FREQ/256/10000000);
}
CloseTimer1();
}// Delaytus

Revision as of 16:11, 15 February 2010

Original Assignment

Do not erase this section!

Your assignment is to create the circuit and code that allows two PIC32s to use wireless communication at high speeds using the Transceiver nRF24L01+ Module with Chip Antenna from Sparkfun.

Read up on the nRF24L01+ Module commands and create functions to allow a PIC32 to initialize and send and receive data.

Test your code by sending 1000 bytes of data from one PIC32 to the other and echo the data back. How long does this transmission take? How far can you separate the PIC32s before the transmission is unreliable?

Overview

The goal of this project is to transmit a byte of data (e.g. a character) from one PIC32/nRF24L01+ board to the other board, and display the received character on a PC screen.

This wiki describes how to wire a nRF24L01+ chip ("wireless chip") to the transmitting PIC32 board ("transmitter") and receiving PIC32 board ("receiver"), and includes annotated code describing the functions that facilitate the wireless communication.

Circuit

Schematic of the nRF24L01+ connected to the PIC32_NU32 board

The wireless chip has 8 pins that need to be wired to the PIC:

(1) Vcc -> +3.3 Vdc supply
(2) CE -> uC pin PORTC.1, configured as GPIO/input
(3) CSN -> uC pin PORTC.2, configured as GPIO/output
(4) SCK -> uC pin PORTC.3/SCK, configured as SCK(SPI)/output
(5) MOSI -> uC pin PORTC.5/SDO, configured as SDO(SPI)/output
(6) MISO -> uC pin PORTC.4/SDI, configured as SDI(SPI)/input
(7) IRQ -> uC pin PORTB.0, configured as GPIO/input
(8) GND -> common digital ground

The +3.3V and ground are provided by the NU32 board. The term "uC" above stands for microcontroller, which is the PIC32 in our case. GPIO stands for General Purpose Input/Output.

Descriptions of the wireless chip's pins can be found in Brennan Ball's DIYembedded 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.

In order to print information from the PIC to the PC, we need to wire an PIC_RS232 cable's transfer and receive lines to the UART ports of the NU32 board (F4, F5).

Code

/* **************************************************************

WirelessTransmitter.c Lab 5: High-speed Wireless Communication Jonathan Drake, Caitlin Ramsey 2010-02-16

This code initializes the nRF24L01+ chip as a transmitter and continuously transmits a character every 100ms. The loop contains code to both output the program's status to the PC via RS232 cable and onboard LEDs.

************************************************************** */


// Includes #include "HardwareProfile.h" #include "nrf24l01.h"

// Function Declarations // Note: Descriptions of functions found after main() function void Initialize(void); void InitializeIO(void); void SpiInitDevice(int chn, int isMaster, int frmEn, int frmMaster); void initUART2(int pbClk); unsigned char spi_send_read_byte(unsigned char byte); void Delayms( unsigned t); void Delayus( unsigned t); void Delaytus( unsigned t);

// Constants #define DESIRED_BAUDRATE (19200) // The desired BaudRate for RS232 communication w/ UART

// Main Function int main(void) { Initialize(); // initialize onboard LEDs, IO pins, UART2, SPI1, set up nRF24L01+ as TX

char RS232_Out_Buffer[64]; // buffer for printing data to the screen via UART unsigned char data = 'x'; // char to be transmitted

// print char to screen sprintf(RS232_Out_Buffer, "data to send = %c\r\n", data); putsUART2(RS232_Out_Buffer);

while(1) { putsUART2("...\r"); // print ... to show transmission nrf24l01_irq_clear_all(); //clear all interrupts in the 24L01 nrf24l01_set_as_tx(); // force 24L01 to be a transmitter (this is a double-check)

//transmit received char over RF, length = 1 byte, true = send away nrf24l01_write_tx_payload(&data, 1, true);

// is the 24L01 activated? if (nrf24l01_irq_pin_active()) { mLED_1_On(); } else { mLED_1_Off(); }

// is the 24L01 an active transmitter? if (nrf24l01_irq_tx_ds_active()) { mLED_2_On(); } else { mLED_2_Off(); }

// wait until the packet has been sent or the maximum number of retries has been reached while(!(nrf24l01_irq_pin_active() && nrf24l01_irq_tx_ds_active()));

// toggle onboard LED 3 to indicate loop iterating mLED_3_Toggle(); Delayms(100); }

}

// Initialize all initialize functions (function descriptions to follow) void Initialize(void) { // initialize peripheral bus clock to SYS_FREQ (80 MHz) int pbClk; pbClk = SYSTEMConfigPerformance(SYS_FREQ);

// initialize UART initUART2(pbClk);

// initialize input/output pins InitializeIO();

// initialize the SPI channel 1 as master, no frame mode SpiInitDevice(1, 1, 0, 0);

//initialize 24L01 to debug configuration as transfer, 1 byte data size, and auto-acknowledge mode disabled nrf24l01_initialize_debug(false, 1, false);

// initialize all onboard LEDs on NU32 mInitAllLEDs();

// if program initialized correctly, indicate on PC & onboard LEDs putsUART2("\r\n***** System Initialized *****\r\n"); mLED_0_On(); }

// initialize IO pins void InitializeIO(void) { TRISBbits.TRISB0 = 1; // set IRQ pin as input TRISC = 0xFFF9; // make CSN, CE digital outputs PORTC = 0x0004; // set CSN bit active }


// initialize UART2 void initUART2(int pbClk) { #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 #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 OpenUART2( config1, config2, pbClk/16/DESIRED_BAUDRATE-1); // calculate actual BAUD generate value. ConfigIntUART2(UART_INT_PR2 | UART_RX_INT_EN); }


// initialize SPI void SpiInitDevice(int chn, int isMaster, int frmEn, int frmMaster) { unsigned int config = SPI_CON_MODE16|SPI_CON_SMP|SPI_CON_ON; // SPI configuration word if(isMaster) { config|=SPI_CON_MSTEN; } if(frmEn) { config|=SPI_CON_FRMEN; if(!frmMaster) { config|=SPI_CON_FRMSYNC; } } SpiChnOpen(chn, config, 4); // divide fpb by 4, configure the I/O ports. Not using SS in this example }

/* ******************************************************

Function: spi_send_read_byte Inputs: unsigned char byte Outputs: unsigned short rxData

This function is required by the 24L01 header file. It takes the inputted byte, sends it over the chosen SPI channel, then waits to retreive data back.

****************************************************** */ unsigned char spi_send_read_byte(unsigned char byte) { unsigned short txData, rxData; // transmit, receive characters int chn = 1; // SPI channel to use (1 or 2)

txData = byte; // take inputted byte and store into txData SpiChnPutC(chn, txData); // send data rxData = SpiChnGetC(chn); // retreive over channel chn the received data into rxData

return rxData; }


/* ******************************************************

Functions: Delayms, Delayus, Delaytus Inputs: unsigned t Outputs: none

These functions are required by the 24L01 header file. They take an input of t (ms, us, us/10) and delay the program.

****************************************************** */ void Delayms( unsigned t) // This uses Timer 1, can be changed to another timer. Assumes FPB = SYS_FREQ { OpenTimer1(T1_ON | T1_PS_1_256, 0xFFFF); while (t--) { // t x 1ms loop WriteTimer1(0); while (ReadTimer1() < SYS_FREQ/256/1000); } CloseTimer1(); } // Delayms

void Delayus( unsigned t) { OpenTimer1(T1_ON | T1_PS_1_256, 0xFFFF); while (t--) { // t x 1ms loop WriteTimer1(0); while (ReadTimer1() < SYS_FREQ/256/1000000); } CloseTimer1(); }// Delayus

void Delaytus( unsigned t) { OpenTimer1(T1_ON | T1_PS_1_256, 0xFFFF); while (t--) { // t x 1ms loop WriteTimer1(0); while (ReadTimer1() < SYS_FREQ/256/10000000); } CloseTimer1(); }// Delaytus