This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

PIC18F4550 with Nordic nRF24L01

I am trying to get wireless communication implemented on a robotics project I am working on. I'm using a PIC18F4550, PIC18F2550, and two Nordic nRF24L01's. I'm having trouble on the transmission side; for some reason the IRQ pin does not toggle to indicate that a packet has been successfully sent.

I've included the code below, any help is much appreciated.


/*
	Wireless communication using a PIC18F4550 (master) and nRF24L01 (slave) - Transmitter
*/

/***************************************************** 
		Includes
**************************************************** */

// Include files
#include <p18cxxx.h>						// Finds correct header for any PIC18
#include <delays.h>							// Enables you to add varying amount of NOPs (Delays)
#include <stdlib.h>
#include <spi.h>							// Just in case we want to cheat with SPI

// Define names for LED pins
//#define LED1 		PORTAbits.RA0			// blinky light (code is running)
#define LED1 		LATAbits.LATA0			// blinky light (code is running)

// Define names for SPI connection pins
//#define CE 			PORTAbits.RA2			// Chip Enable (CE)			-- Pin that activates RX or TX mode
#define CE 			LATAbits.LATA2			// Chip Enable (CE)			-- Pin that activates RX or TX mode
#define IRQ 		PORTBbits.RB2			// Interrupt Request (IRQ)	-- Pin that signals transmission
#define SDO 		TRISCbits.TRISC7		// Serial Data Out (SDO)	-- Pin that data goes out from
#define SDI 		TRISBbits.TRISB0		// Serial Data In (SDI)		-- Pin that data comes in to
#define SCK 		TRISBbits.TRISB1		// Serial Clock (SCK)		-- Pin that sends clock signal to sync all  SPI devices

// Define names for "Slave Select" pins
//#define SS  		PORTAbits.RA4			// Slave Select (SS)		-- Pin that selects "slave" module to communicate with
#define SS  		LATAbits.LATA4			// Slave Select (SS)		-- Pin that selects "slave" module to communicate with

#define select 		0						// Device is "active low," define "select" as 0
#define deselect	1

// Define names for SPI configuration pins
#define SMP			SSPSTATbits.SMP			// Sample Bit (SMP)			-- Pin that sets where to sample data
#define CKP			SSPCON1bits.CKP			// Clock Polarity (CKP)		-- Pin that sets where SCK will idle
#define CKE			SSPSTATbits.CKE			// Clock Edge Select (CKE)	-- Pin that sets which transition transmission takes place
#define SSPEN		SSPCON1bits.SSPEN		// Serial Prt Enbl (SSPEN)	-- Pin that will enable serial port and configure SCK, SDO, SDI and SS as serial port pins

#define WCOL		SSPCON1bits.WCOL		// Write Collision (WCOL)	-- Detect bit
//#define WCOL_LED	PORTCbits.RC1			// Write Collision (WCOL)	-- Pin for collision visual
#define WCOL_LED	LATCbits.LATC1			// Write Collision (WCOL)	-- Pin for collision visual

// Define commands for Nordic via SPI
#define R_REGISTER		0x00
#define W_REGISTER		0x20
#define R_RX_PAYLOAD	0x61
#define W_TX_PAYLOAD	0xA0
#define FLUSH_TX		0xE1
#define FLUSH_RX		0xE2
#define REUSE_TX_PL		0xE3
#define NOP				0xFF

// Define Nordic registers
#define CONFIG			0x00
#define EN_AA			0x01
#define EN_RXADDR		0x02
#define SETUP_AW		0x03
#define SETUP_RETR		0x04
#define RF_CH			0x05
#define RF_SETUP		0x06
#define STATUS			0x07
#define OBSERVE_TX		0x08
#define CD				0x09
#define RX_ADDR_P0		0x0A
#define RX_ADDR_P1		0x0B
#define RX_ADDR_P2		0x0C
#define RX_ADDR_P3		0x0D
#define RX_ADDR_P4		0x0E
#define RX_ADDR_P5		0x0F
#define TX_ADDR			0x10
#define RX_PW_P0		0x11
#define RX_PW_P1		0x12
#define RX_PW_P2		0x13
#define RX_PW_P3		0x14
#define RX_PW_P4		0x15
#define RX_PW_P5		0x16
#define FIFO_STATUS		0x17

/***************************************************** 
		Function Prototypes & Variables
**************************************************** */ 

void initChip(void);
void init_spi_master(void);
void init_nordic(void);
void InterruptHandler_SPI(void);
void InterruptHandler_Nordic(void);
void delay(void);
void spi_write(int data);
void transmit_data(int data);

unsigned char spi_transmission_done;
unsigned char data_sent;
unsigned char data;
unsigned char dummy;

/*************************************************
  RESET VECTORS: REMOVE IF NOT USING BOOTLOADER!!!
**************************************************/

extern void _startup (void);        
#pragma code _RESET_INTERRUPT_VECTOR = 0x000800
void _reset (void)
{
    _asm goto _startup _endasm
}
#pragma code

/*************************************************
  Interrupt Service Routines
**************************************************/

#pragma code _HIGH_INTERRUPT_VECTOR = 0x000808
void _high_ISR (void)
{
	InterruptHandler_SPI();
	InterruptHandler_Nordic();
}
#pragma code

#pragma code _LOW_INTERRUPT_VECTOR = 0x000818
void _low_ISR (void)
{
	InterruptHandler_Nordic();
} 
#pragma code

void delay() {
	int counter = 0;
    for (counter = 0; counter<30000; counter++) {
        ;
				}
}

/********************************************************* 
	Interrupt Handlers
**********************************************************/

#pragma interrupt InterruptHandler_SPI

void InterruptHandler_SPI(void) {
   if(PIR1bits.SSPIF == 1)	// SPI Interrupt
	{
		PIR1bits.SSPIF = 0; // clear interrupt
		spi_transmission_done = 1;
	}		
}

#pragma interrupt InterruptHandler_Nordic

void InterruptHandler_Nordic(void) {
	if(INTCON3bits.INT2IF == 1)	// Nordic Interrupt
	{
		INTCON3bits.INT2IF = 0; // clear interrupt
//		spi_write(W_REGISTER+STATUS); // Write to the STATUS register
//		spi_write(0b01111110);		  	  // Reset
//		spi_write(FLUSH_TX); 		    // Flush the FIFO
		data_sent = 1;
	}
}

/*************************************************
			Initialize the PIC
**************************************************/

void initChip(){
	PORTA = 0x00;			// reset all PORT registers
	PORTB = 0x00;
	PORTC = 0x00;
	PORTD = 0x00;
	PORTE = 0x00;
	
	TRISA = 0x00;			// set all PORTA to be OUTPUT
	TRISB = 0b00000101;		// set RB0 and RB2 as INPUT
							// and the rest of PORTB as OUTPUT
	TRISC = 0x00;			// set all PORTC to be OUTPUT
	TRISD = 0x00;			// set all PORTD to be OUTPUT
	TRISE = 0x00;			// set up PORTE to be OUTPUT
	
	ADCON1 = 0b00001111;	// set up PORTA to be digital I/Os
	
	spi_transmission_done = 0; // initilize variables
	data_sent = 0;
	dummy = 0b00000000;
	data = 0b11111111;
}

/*************************************************
			Initialize the SPI Master
**************************************************/

void init_spi_master() {

	SDI = 1;	// Serial Data In 			- enable master mode
	SCK = 0;	// Serial Clock				- clear TRISB1 for master
	SDO = 0;	// Serial Data Out 			- clear TRISC7
	SS = deselect;

	SMP = 0;	// Sample bit 				- sample in middle
	CKP = 0;	// Clock Polarity			- low when idle		**MUST BE SAME ON MASTER AND SLAVE**
	CKE = 0;	// Clock Edge Select		- transmit on transition from idle clock state to active
	
	SSPCON1bits.SSPM3 = 0;	// Set the clock rate in master mode
	SSPCON1bits.SSPM2 = 0;	// to be FOSC/16 (Frequency of Oscillation)
	SSPCON1bits.SSPM1 = 0;
	SSPCON1bits.SSPM0 = 1;
	
	SSPEN = 0;	// Wait to enable serial port and configure SCK, SDO, SDI and SS as serial port pins

	PIE1bits.SSPIE = 1;	// enable SPI interrupt
}

/*************************************************
			Initialize the Nordic
**************************************************/

void init_nordic() {
	
	RCONbits.IPEN = 1;			// enable priorities levels on interrupts
	INTCON3bits.INT2IE = 1;		// enable the INT2 (IRQ) external interrupt
	INTCON3bits.INT2IP = 1;		// IRQ is high priority
	INTCON2bits.INTEDG2 = 0;	// IRQ is triggered on falling edge
	
	spi_write(W_REGISTER+CONFIG); 	// Write to the CONFIG register
	spi_write(0b01001110);		  	  // [7] Reserved
									  // [6] RX_DR Interrupt 1 - mask
									  // [5] TX_DS Interrupt 0 - unmask
									  // [4] MAX_RT Interrupt
									  // [3] Enable CRC
									  // [2] 2 byte CRC
									  // [1] PWR_UP
									  // [0] TX
	spi_write(W_REGISTER+SETUP_AW); // Write to the SETUP_AW register
	spi_write(0b00000011);		  	  // Set the width to 5 bytes
	spi_write(FLUSH_TX); 		    // Flush the FIFO
	
	CE = 0;						    // hold CE low to transmit
}

/*************************************************
			Functions for Writing Data
**************************************************/

void spi_write(int data) {
	
	SSPEN = 1;			   // Enable serial port and configure SCK, SDO, SDI and SS as serial port pins
	
	if(WCOL == 0) { 	   // collision testing
		SS = select;
		SSPBUF = data;
		SS = deselect;		
	}
	else {				   // there is a collision
		WCOL = 0;
		WCOL_LED = !WCOL_LED; //visual to see a collision
	}
	delay();  // band-aid that fixes collisions during multiple writes
}

void transmit_data(int data) {
	data_sent = 0;
	spi_write(W_TX_PAYLOAD);	// send command for transmission
	spi_write(data);			// load data
	
	CE = 1;						// toggle CE for >10ns to send packet
	delay(); 			
	CE = 0;
}

/******************************************************************************/
/* Main Program                                                               */
/******************************************************************************/

void main() {

	initChip();
	init_spi_master();
	init_nordic();
	INTCONbits.GIEH = 1;    // enables all high priority interrupts
	INTCONbits.GIEL = 1;    // enables all low priority interrupts
	transmit_data(data);	// send some data

	while (1) {
		LED1 = !LED1; 		// toggle LED - program is running
		dummy = SSPBUF;		// in case there is something in there, get rid of it
				
		if(IRQ == 0){
				PORTD = 0b11111111;
		}

		if(spi_transmission_done == 1){
				dummy = SSPBUF;
				spi_transmission_done = 0;
		}		
		
		if(data_sent == 1){
				PORTD = 0b11111111;
				transmit_data(data);	// send some more data
		}
				
		delay(); // LED blinks	
		data++;
	}
}


Parents Reply Children
  • For some reason the PWR_UP bit is still not being set... Any ideas?

    /***************************************************** Includes **************************************************** */

    // Include files #include // Finds correct header for any PIC18 #include // Enables you to add varying amount of NOPs (Delays) #include #include // Just in case we want to cheat with SPI

    // Define names for LED pins #define LED1 LATAbits.LATA0 // blinky light (code is running)

    // Define names for SPI connection pins #define CE LATAbits.LATA2 // Chip Enable (CE) -- Pin that activates RX or TX mode #define IRQ PORTBbits.RB2 // Interrupt Request (IRQ) -- Pin that signals transmission #define SDO TRISCbits.TRISC7 // Serial Data Out (SDO) -- Pin that data goes out from #define SDI TRISBbits.TRISB0 // Serial Data In (SDI) -- Pin that data comes in to #define SCK TRISBbits.TRISB1 // Serial Clock (SCK) -- Pin that sends clock signal to sync all SPI devices

    // Define names for "Slave Select" pins #define SS LATAbits.LATA4 // Slave Select (SS) -- Pin that selects "slave" module to communicate with

    #define select 0 // Device is "active low," define "select" as 0 #define deselect 1

    // Define names for SPI configuration pins #define SMP SSPSTATbits.SMP // Sample Bit (SMP) -- Pin that sets where to sample data #define CKP SSPCON1bits.CKP // Clock Polarity (CKP) -- Pin that sets where SCK will idle #define CKE SSPSTATbits.CKE // Clock Edge Select (CKE) -- Pin that sets which transition transmission takes place #define SSPEN SSPCON1bits.SSPEN // Serial Prt Enbl (SSPEN) -- Pin that will enable serial port and configure SCK, SDO, SDI and SS as serial port pins

    #define WCOL SSPCON1bits.WCOL // Write Collision (WCOL) -- Detect bit #define WCOL_LED LATCbits.LATC0 // Write Collision (WCOL) -- Pin for collision visual #define MAXRT_LED LATCbits.LATC1 // MAX_RT -- Pin for max retries visual #define TX_LED LATCbits.LATC2 // TX_DS -- Pin for transmission successful visual

    // Define commands for Nordic via SPI #define R_REGISTER 0x00 #define W_REGISTER 0x20

    // Define Nordic registers #define CONFIG 0x00 #define STATUS 0x07

    /***************************************************** Function Prototypes & Variables **************************************************** */

    void initChip(void); void init_spi_master(void); void init_nordic(void); void InterruptHandler_SPI(void); void DelayMS(unsigned long milliseconds); void spi_write(int data);

    unsigned char spi_transmission_done;

    /************************************************* RESET VECTORS: REMOVE IF NOT USING BOOTLOADER!!! **************************************************/

    extern void _startup (void);
    #pragma code _RESET_INTERRUPT_VECTOR = 0x000800 void _reset (void) { _asm goto _startup _endasm } #pragma code

    /************************************************* Interrupt Service Routines **************************************************/

    //#pragma code _HIGH_INTERRUPT_VECTOR = 0x000808 //void _high_ISR (void) //{ // InterruptHandler_SPI(); //} //#pragma code

    void DelayMS(unsigned long milliseconds) { unsigned long count;

    for(count = 0; count ad the CONFIG register
    SS = deselect;
    	
    

    }

    /************************************************* Functions for Writing Data **************************************************/

    void spi_write(int data) {

    SSPEN = 1;			   // Enable serial port and configure SCK, SDO, SDI and SS as serial port pins
    
    if(WCOL == 0) { 	   // collision testing
    	SSPBUF = data;
    }
    else {				   // there is a collision
    	WCOL = 0;
    	WCOL_LED = !WCOL_LED; //visual to see a collision
    }
    
    while(!DataRdySPI());
    
    PORTD = SSPBUF;
    

    }

    // / Main Program / //

    void main() { initChip(); init_spi_master(); // INTCONbits.GIEH = 1; // enables all high priority interrupts // INTCONbits.GIEL = 1; // enables all low priority interrupts init_nordic(); while (1){ } }

  • For some reason the PWR_UP bit is still not being set... Any ideas?

    /***************************************************** Includes **************************************************** */

    // Include files #include // Finds correct header for any PIC18 #include // Enables you to add varying amount of NOPs (Delays) #include #include // Just in case we want to cheat with SPI

    // Define names for LED pins #define LED1 LATAbits.LATA0 // blinky light (code is running)

    // Define names for SPI connection pins #define CE LATAbits.LATA2 // Chip Enable (CE) -- Pin that activates RX or TX mode #define IRQ PORTBbits.RB2 // Interrupt Request (IRQ) -- Pin that signals transmission #define SDO TRISCbits.TRISC7 // Serial Data Out (SDO) -- Pin that data goes out from #define SDI TRISBbits.TRISB0 // Serial Data In (SDI) -- Pin that data comes in to #define SCK TRISBbits.TRISB1 // Serial Clock (SCK) -- Pin that sends clock signal to sync all SPI devices

    // Define names for "Slave Select" pins #define SS LATAbits.LATA4 // Slave Select (SS) -- Pin that selects "slave" module to communicate with

    #define select 0 // Device is "active low," define "select" as 0 #define deselect 1

    // Define names for SPI configuration pins #define SMP SSPSTATbits.SMP // Sample Bit (SMP) -- Pin that sets where to sample data #define CKP SSPCON1bits.CKP // Clock Polarity (CKP) -- Pin that sets where SCK will idle #define CKE SSPSTATbits.CKE // Clock Edge Select (CKE) -- Pin that sets which transition transmission takes place #define SSPEN SSPCON1bits.SSPEN // Serial Prt Enbl (SSPEN) -- Pin that will enable serial port and configure SCK, SDO, SDI and SS as serial port pins

    #define WCOL SSPCON1bits.WCOL // Write Collision (WCOL) -- Detect bit #define WCOL_LED LATCbits.LATC0 // Write Collision (WCOL) -- Pin for collision visual #define MAXRT_LED LATCbits.LATC1 // MAX_RT -- Pin for max retries visual #define TX_LED LATCbits.LATC2 // TX_DS -- Pin for transmission successful visual

    // Define commands for Nordic via SPI #define R_REGISTER 0x00 #define W_REGISTER 0x20

    // Define Nordic registers #define CONFIG 0x00 #define STATUS 0x07

    /***************************************************** Function Prototypes & Variables **************************************************** */

    void initChip(void); void init_spi_master(void); void init_nordic(void); void InterruptHandler_SPI(void); void DelayMS(unsigned long milliseconds); void spi_write(int data);

    unsigned char spi_transmission_done;

    /************************************************* RESET VECTORS: REMOVE IF NOT USING BOOTLOADER!!! **************************************************/

    extern void _startup (void);
    #pragma code _RESET_INTERRUPT_VECTOR = 0x000800 void _reset (void) { _asm goto _startup _endasm } #pragma code

    /************************************************* Interrupt Service Routines **************************************************/

    //#pragma code _HIGH_INTERRUPT_VECTOR = 0x000808 //void _high_ISR (void) //{ // InterruptHandler_SPI(); //} //#pragma code

    void DelayMS(unsigned long milliseconds) { unsigned long count;

    for(count = 0; count ad the CONFIG register
    SS = deselect;
    	
    

    }

    /************************************************* Functions for Writing Data **************************************************/

    void spi_write(int data) {

    SSPEN = 1;			   // Enable serial port and configure SCK, SDO, SDI and SS as serial port pins
    
    if(WCOL == 0) { 	   // collision testing
    	SSPBUF = data;
    }
    else {				   // there is a collision
    	WCOL = 0;
    	WCOL_LED = !WCOL_LED; //visual to see a collision
    }
    
    while(!DataRdySPI());
    
    PORTD = SSPBUF;
    

    }

    // / Main Program / //

    void main() { initChip(); init_spi_master(); // INTCONbits.GIEH = 1; // enables all high priority interrupts // INTCONbits.GIEL = 1; // enables all low priority interrupts init_nordic(); while (1){ } }

Related