megacrypto
Junior Member level 2
Been working on this for months now, learning from scratch all about programming in C, MCUs, SPI, Registers, and now the nRF24 module. I looked at hundreds of codes (I learn through trial and error - get a working code then learn about every part about it by trying things here and there). I finally got to get the SPI working to communicate between the 2 PIC16F886 (code in XC8), and that was my first step (posted my result in https://www.edaboard.com/threads/324784/)
My objective has been always to get the nRF24 working (i want to play around with light control, curtains, ect.). This is the most I got so far (and I have been honestly through every single code & article there is out there for the nRF24L01 and PICs (most of them are for the PIC18's and many are in CCS).
Anyways, this is how far I got:
My SPI files:
spi.h
spi.c
and these work (they are the ones I used for the master PIC in the above link when directly connected the two PICs via SPI) and I know that with the nRF the PIC is the master and the nRF is the slave, so I used the same files for both PICs connected to the nRF modules.
Now this is where I have been stuck for the last months. This is the code for the TX side:
main.c (TX):
and this is the main.c (RX) side:
i truly would love to get this working and really would appreciate anyone who is willing to give the time to help me out here.
- - - Updated - - -
This is the original code I used, it was written for PIC18F4520 (maybe someone could tell me where I went wrong)
tx.c:
and this is the rx.c:
I changed (used) the SPI function that I made (and worked for communicating between the 2 PICs) and also the "dly" function I removed and used the delays I always use.
I balded the parts that I removed or changed
My objective has been always to get the nRF24 working (i want to play around with light control, curtains, ect.). This is the most I got so far (and I have been honestly through every single code & article there is out there for the nRF24L01 and PICs (most of them are for the PIC18's and many are in CCS).
Anyways, this is how far I got:
My SPI files:
spi.h
Code:
#ifndef SPI_H
#define SPI_H
#ifdef __cplusplus
extern "C" {
#endif
void SPI_Init();
unsigned char SPI_Send(unsigned char data);
#ifdef __cplusplus
}
#endif
#endif /* SPI_H */
spi.c
Code:
#include <xc.h>
#include "spi.h"
void SPI_Init()
{
// INTCON = 0; // Disable all interrupts
TRISC3 = 0; // SCK=RC3 is the serial clock
TRISC4 = 1; // SDI=RC4 is serial data input
TRISC5 = 0; // SDO=RC5 is serial data output
SMP = 0; // Input data sampled at middle data output time
CKP = 1; // Idle state for clock is a high level
CKE = 0; // Transmit occurs on idle to active clock state
SSPEN = 1; // Enables serial port
SSPIF = 0;
SSPM3 = 0; //
SSPM2 = 0; //
SSPM1 = 0; //
SSPM0 = 1; // SPI Master mode, clock = FOSC/16
}
unsigned char SPI_Send(unsigned char data)
{
SSPBUF = data; // Put command into SPI buffer
while (!BF); // Wait for the transfer to finish
return SSPBUF; // Save the read value
}
and these work (they are the ones I used for the master PIC in the above link when directly connected the two PICs via SPI) and I know that with the nRF the PIC is the master and the nRF is the slave, so I used the same files for both PICs connected to the nRF modules.
Now this is where I have been stuck for the last months. This is the code for the TX side:
main.c (TX):
Code:
#include <xc.h>
// CONFIG1
#pragma config FOSC = INTRC_NOCLKOUT, WDTE = OFF, PWRTE = OFF, MCLRE = OFF
#pragma config CP = OFF, CPD = OFF, BOREN = OFF, IESO = OFF, FCMEN = OFF
#pragma config LVP = OFF, DEBUG = OFF
// CONFIG2
#pragma config BOR4V = BOR40V, WRT = OFF
// Set Clock Freq. & Delays
#ifndef _XTAL_FREQ
#define _XTAL_FREQ 8000000
#define __delay_us(x) _delay((unsigned long)((x)*(_XTAL_FREQ/8000000.0)))
#define __delay_ms(x) _delay((unsigned long)((x)*(_XTAL_FREQ/8000.0)))
#endif
#include "spi.h"
void Init(void);
void transmit_data(void);
void configure_transmitter(void);
unsigned char spi1_send_read_byte(unsigned char byte);
// Defines
#define SPI_SCK RC3 // Clock pin, PORTC pin 3
#define SPI_SO RC5 // Serial output pin, PORTC pin 5
#define SPI_SI RC4 // Serial input pin, PORTC pin 4
#define SPI_CSN RC2 // CSN output pin, PORTC pin 2
#define SPI_CE RC1 // CE output pin, PORTC pin 1
#define SPI_IRQ RB0 // IRQ input pin, PORTB pin 0
#define SPI_SCALE 4 // postscaling of signal
#define LED RA0
#define PB RA1
void main(){
Init();
SPI_Init();
configure_transmitter();
while(1){
transmit_data();
LED = 1;
__delay_ms(200); //200 ms delay
LED = 0;
__delay_ms(3270); //3.27 s delay
}
}
void Init(void)
{
PORTA = 0x00;
ADCON1 = 0x0F; // set up PORTA to be digital I/Os
TRISA = 0x02; // PORTA<7.2,0> outputs PORTA<1> input
TRISBbits.TRISB0 = 1; // IRQ input
TRISCbits.TRISC1 = 0; // CE output
TRISCbits.TRISC2 = 0; // CSN output
}
void configure_transmitter(void)
{
unsigned char i, j, data, cmd;
SPI_CE = 0;
SPI_CSN = 0;
// PTX, CRC enabled, mask a couple of ints
SPI_Send(0x20);
SPI_Send(0x38);
SPI_CSN = 1;
SPI_CSN = 0;
//auto retransmit off
SPI_Send(0x24);
SPI_Send(0x00);
SPI_CSN = 1;
SPI_CSN = 0;
//address width = 5
SPI_Send(0x23);
SPI_Send(0x03);
SPI_CSN = 1;
SPI_CSN = 0;
//data rate = 1MB
SPI_Send(0x26);
SPI_Send(0x07);
SPI_CSN = 1;
SPI_CSN = 0;
//set channel 2, this is default but we did it anyway...
SPI_Send(0x25);
SPI_Send(0x02);
SPI_CSN = 1;
SPI_CSN = 0;
//set address E7E7E7E7E7, also default...
SPI_Send(0x30);
for (j = 0; j < 5; j++)
{
SPI_Send(0xE7);
}
SPI_CSN = 1;
SPI_CSN = 0;
//disable auto-ack, RX mode
//shouldn't have to do this, but it won't TX if you don't
SPI_Send(0x21);
SPI_Send(0x00);
SPI_CSN = 1;
}
void transmit_data(void)
{
unsigned char i, data, cmd;
SPI_CSN = 0;
//clear previous ints
SPI_Send(0x27);
SPI_Send(0x7E);
SPI_CSN = 1;
SPI_CSN = 0;
//PWR_UP = 1
SPI_Send(0x20);
SPI_Send(0x3A);
SPI_CSN = 1;
SPI_CSN = 0;
//clear TX fifo
//the data sheet says that this is supposed to come up 0 after POR, but that doesn't seem to be the case
SPI_Send(0xE1);
SPI_CSN = 1;
SPI_CSN = 0;
//4 byte payload
SPI_Send(0xA0);
SPI_Send(0x34);
SPI_Send(0x33);
SPI_Send(0x32);
SPI_Send(0x31);
SPI_CSN = 1;
//Pulse CE to start transmission
SPI_CE = 1;
__delay_ms(69); //delay 69 ms
SPI_CE = 0;
}
and this is the main.c (RX) side:
Code:
#include <xc.h>
// CONFIG1
#pragma config FOSC = INTRC_NOCLKOUT, WDTE = OFF, PWRTE = OFF, MCLRE = OFF
#pragma config CP = OFF, CPD = OFF, BOREN = OFF, IESO = OFF, FCMEN = OFF
#pragma config LVP = OFF, DEBUG = OFF
// CONFIG2
#pragma config BOR4V = BOR40V, WRT = OFF
// Set Clock Freq. & Delays
#ifndef _XTAL_FREQ
#define _XTAL_FREQ 8000000
#define __delay_us(x) _delay((unsigned long)((x)*(_XTAL_FREQ/8000000.0)))
#define __delay_ms(x) _delay((unsigned long)((x)*(_XTAL_FREQ/8000.0)))
#endif
#include "spi.h"
void Init(void);
void reset_RX(void);
void configure_RX(void);
// Defines
#define SPI_SCK RC3 // Clock pin, PORTC pin 3
#define SPI_SO RC5 // Serial output pin, PORTC pin 5
#define SPI_SI RC4 // Serial input pin, PORTC pin 4
#define SPI_CSN RC2 // CSN output pin, PORTC pin 2
#define SPI_CE RC1 // CE output pin, PORTC pin 1
#define SPI_IRQ RB0 // IRQ input pin, PORTB pin 0
#define SPI_SCALE 4 // postscaling of signal
#define LED RA0
#define PB RA1
void main(){
Init();
SPI_Init();
configure_RX();
unsigned char i;
while(1){
if (SPI_IRQ == 0) //wait for anything
{
for (i = 0; i < 5; i++) //flash LED 5 times if data received
{
LED = 1;
__delay_ms(200); // 200 ms delay
LED = 0;
__delay_ms(196); // 196 ms
}
__delay_ms(196); // 196 ms
reset_RX();
}
}
}
void Init(void)
{
PORTA = 0x00;
ADCON1 = 0x0F; // set up PORTA to be digital I/Os
TRISA = 0x02; // PORTA<7.2,0> outputs PORTA<1> input
TRISBbits.TRISB0 = 1; // IRQ input
TRISCbits.TRISC1 = 0; // CE output
TRISCbits.TRISC2 = 0; // CSN output
}
//configure nRF24L01 for receive
void configure_RX(void)
{
unsigned char i, j;
SPI_CSN = 0;
SPI_CE = 0;
//PRX, CRC enabled
SPI_Send(0x20);
SPI_Send(0x39);
SPI_CSN = 1;
SPI_CSN = 0;
//disable auto-ack for all channels
SPI_Send(0x21);
SPI_Send(0x00);
SPI_CSN = 1;
SPI_CSN = 0;
//address width = 5 bytes
SPI_Send(0x23);
SPI_Send(0x03);
SPI_CSN = 1;
SPI_CSN = 0;
//data rate = 1MB
SPI_Send(0x26);
SPI_Send(0x07);
SPI_CSN = 1;
SPI_CSN = 0;
//4 byte payload
SPI_Send(0x31);
SPI_Send(0x04);
SPI_CSN = 1;
SPI_CSN = 0;
//set channel 2
SPI_Send(0x25);
SPI_Send(0x02);
SPI_CSN = 1;
SPI_CSN = 0;
//set address E7E7E7E7E7
SPI_Send(0x30);
for (j = 0; j < 5; j++)
SPI_Send(0xE7);
SPI_CSN = 1;
SPI_CSN = 0;
//PWR_UP = 1
SPI_Send(0x20);
SPI_Send(0x3B);
SPI_CSN = 1;
SPI_CE = 1;
}
void reset_RX(void)
{
unsigned char i, j;
unsigned char buffer[4];
//Read RX payload
SPI_CSN = 0;
SPI_Send(0x61);
for (j = 0; j < 4; j++)
{
buffer[j] = SPI_Send(0);
}
SPI_CSN = 1;
//Flush RX FIFO
SPI_CSN = 0;
SPI_Send(0xE2);
SPI_CSN = 1;
SPI_CSN = 0;
//reset int
SPI_Send(0x27);
SPI_Send(0x40);
SPI_CSN = 1;
}
i truly would love to get this working and really would appreciate anyone who is willing to give the time to help me out here.
- - - Updated - - -
This is the original code I used, it was written for PIC18F4520 (maybe someone could tell me where I went wrong)
tx.c:
Code:
/*
** Tx.c
** Transmit test program for PIC18F4520 and nRF24L01 or nRF24L01+
** Uses the Microchip C18 compiler
** Based on SFE code for the CC5X compiler in 24L01demo_V01.c
*/
[B][COLOR="#0000FF"]#include <p18cxxx.h>
#include <spi.h>
#include <timers.h>[/COLOR][/B]
[B][COLOR="#FF0000"]// Pragmas
#pragma config OSC = INTIO67
#pragma config PWRT = ON
//#pragma config MCLRE = OFF
#pragma config BOREN = OFF[/COLOR][/B]
//function prototypes
void init(void);
void transmit_data(void);
void configure_transmitter(void);
[COLOR="#FF0000"][B]unsigned char spi_Send_Read(unsigned char);
unsigned char spi1_send_read_byte(unsigned char byte);
void dly(unsigned int);[/B][/COLOR]
// Defines
[COLOR="#0000FF"]#define SPI_SCK LATCbits.LATC3 // Clock pin, PORTC pin 3
#define SPI_SO LATCbits.LATC5 // Serial output pin, PORTC pin 5
#define SPI_SI PORTCbits.RC4 // Serial input pin, PORTC pin 4
#define SPI_CSN LATCbits.LATC2 // CSN output pin, PORTC pin 2
#define SPI_CE LATCbits.LATC1 // CE output pin, PORTC pin 1
#define SPI_IRQ PORTBbits.RB0 // IRQ input pin, PORTB pin 0
#define SPI_SCALE 4 // postscaling of signal
#define LED LATAbits.LATA0
#define PB PORTAbits.RA1[/COLOR]
[COLOR="#FF0000"][B]// Macros
#define nop() _asm nop _endasm
[/B][/COLOR]
void main(void)
{
init();
configure_transmitter();
while (1)
{
transmit_data();
LED = 1;
dly(63973); //200 ms delay
LED = 0;
dly(40000); //3.27 s delay
nop();
}
}
void init(void)
{
[COLOR="#FF0000"][B] // run internal oscillator at 8 MHz
OSCCON = OSCCON | 0x70;
while (OSCCONbits.IOFS == 0)
;[/B][/COLOR]
[COLOR="#0000FF"] PORTA = 0x00;
ADCON1 = 0x0F; // set up PORTA to be digital I/Os
TRISA = 0x02; // PORTA<7.2,0> outputs PORTA<1> input
TRISCbits.TRISC3 = 0; // SDO output
TRISCbits.TRISC5 = 0; // SCK output
TRISCbits.TRISC2 = 0; // CSN output
TRISCbits.TRISC1 = 0; // CE output
TRISBbits.TRISB0 = 1; // IRQ input[/COLOR]
[COLOR="#FF0000"][B] OpenSPI(SPI_FOSC_16, MODE_00, SMPMID); //open SPI1
OpenTimer0( TIMER_INT_OFF &
T0_16BIT &
T0_SOURCE_INT &
T0_PS_1_256 );[/B][/COLOR]
}
void configure_transmitter(void)
{
unsigned char i, j, data, cmd;
SPI_CE = 0;
SPI_CSN = 0;
// PTX, CRC enabled, mask a couple of ints
spi_Send_Read(0x20);
spi_Send_Read(0x38);
SPI_CSN = 1;
SPI_CSN = 0;
//auto retransmit off
spi_Send_Read(0x24);
spi_Send_Read(0x00);
SPI_CSN = 1;
SPI_CSN = 0;
//address width = 5
spi_Send_Read(0x23);
spi_Send_Read(0x03);
SPI_CSN = 1;
SPI_CSN = 0;
//data rate = 1MB
spi_Send_Read(0x26);
spi_Send_Read(0x07);
SPI_CSN = 1;
SPI_CSN = 0;
//set channel 2, this is default but we did it anyway...
spi_Send_Read(0x25);
spi_Send_Read(0x02);
SPI_CSN = 1;
SPI_CSN = 0;
//set address E7E7E7E7E7, also default...
spi_Send_Read(0x30);
for (j = 0; j < 5; j++)
{
spi_Send_Read(0xE7);
}
SPI_CSN = 1;
SPI_CSN = 0;
//disable auto-ack, RX mode
//shouldn't have to do this, but it won't TX if you don't
spi_Send_Read(0x21);
spi_Send_Read(0x00);
SPI_CSN = 1;
}
void transmit_data(void)
{
unsigned char i, data, cmd;
SPI_CSN = 0;
//clear previous ints
spi_Send_Read(0x27);
spi_Send_Read(0x7E);
SPI_CSN = 1;
SPI_CSN = 0;
//PWR_UP = 1
spi_Send_Read(0x20);
spi_Send_Read(0x3A);
SPI_CSN = 1;
SPI_CSN = 0;
//clear TX fifo
//the data sheet says that this is supposed to come up 0 after POR, but that doesn't seem to be the case
spi_Send_Read(0xE1);
SPI_CSN = 1;
SPI_CSN = 0;
//4 byte payload
spi_Send_Read(0xA0);
spi_Send_Read(0x34);
spi_Send_Read(0x33);
spi_Send_Read(0x32);
spi_Send_Read(0x31);
SPI_CSN = 1;
//Pulse CE to start transmission
SPI_CE = 1;
dly(65000); //delay 69 ms
SPI_CE = 0;
}
[COLOR="#FF0000"][B]unsigned char spi_Send_Read(unsigned char byte)
{
SSPBUF = byte;
while(!DataRdySPI())
;
return SSPBUF;
}
void dly(unsigned int c)
{
INTCONbits.TMR0IF = 0;
WriteTimer0(c);
while (INTCONbits.TMR0IF == 0)
;
}[/B][/COLOR]
and this is the rx.c:
Code:
/*
** Rx.c
** Receive test program for PIC18F4520 and nRF24L01 or nRF24L01+
** Uses the Microchip C18 compiler
** Based on SFE code for the CC5X compiler in 24L01demo_V01.c
**
** The LED is flashed five times when data are received.
** The received data in the buffer may be checked using the
** debugger Watch window.*/
#include <p18cxxx.h>
#include <spi.h>
#include <timers.h>
// Pragmas
#pragma config OSC = INTIO67
#pragma config PWRT = ON
#pragma config MCLRE = OFF
#pragma config BOREN = OFF
//function prototypes
void init(void);
void reset_RX(void);
void configure_RX(void);
unsigned char spi_Send_Read(unsigned char);
void dly(unsigned int);
// Defines
#define SPI_SCK LATCbits.LATC3 // Clock pin, PORTC pin 3
#define SPI_SO LATCbits.LATC5 // Serial output pin, PORTC pin 5
#define SPI_SI PORTCbits.RC4 // Serial input pin, PORTC pin 4
#define SPI_CSN LATCbits.LATC2 // CSN output pin, PORTC pin 2
#define SPI_CE LATCbits.LATC1 // CE output pin, PORTC pin 1
#define SPI_IRQ PORTBbits.RB0 // IRQ input pin, PORTB pin 0
#define SPI_SCALE 4 // postscaling of signal
#define LED LATAbits.LATA0
#define PB PORTAbits.RA1
// Macros
#define nop() _asm nop _endasm
void main(void)
{
unsigned char i;
init();
configure_RX();
while(1)
{
if (SPI_IRQ == 0) //wait for anything
{
for (i = 0; i < 5; i++) //flash LED 5 times if data received
{
LED = 1;
dly(63973); // 200 ms delay
LED = 0;
dly(63973); // 196 ms
}
dly(63973); // 196 ms
reset_RX();
}
}
}
// initialise 18F4520
void init(void)
{
// run internal oscillator at 8 MHz
OSCCON = OSCCON | 0x70;
while (OSCCONbits.IOFS == 0)
;
PORTA = 0x00;
ADCON1 = 0x0F; // set up PORTA to be digital I/Os
TRISA = 0x02; // PORTA<7.2,0> outputs PORTA<1> input
TRISCbits.TRISC3 = 0; // SDO output
TRISCbits.TRISC5 = 0; // SCK output
TRISCbits.TRISC2 = 0; // CSN output
TRISCbits.TRISC1 = 0; // CE output
TRISBbits.TRISB0 = 1; // IRQ input
OpenSPI(SPI_FOSC_16, MODE_00, SMPMID); //open SPI1
OpenTimer0( TIMER_INT_OFF &
T0_16BIT &
T0_SOURCE_INT &
T0_PS_1_256 );
}
//configure nRF24L01 for receive
void configure_RX(void)
{
unsigned char i, j;
SPI_CSN = 0;
SPI_CE = 0;
//PRX, CRC enabled
spi_Send_Read(0x20);
spi_Send_Read(0x39);
SPI_CSN = 1;
SPI_CSN = 0;
//disable auto-ack for all channels
spi_Send_Read(0x21);
spi_Send_Read(0x00);
SPI_CSN = 1;
SPI_CSN = 0;
//address width = 5 bytes
spi_Send_Read(0x23);
spi_Send_Read(0x03);
SPI_CSN = 1;
SPI_CSN = 0;
//data rate = 1MB
spi_Send_Read(0x26);
spi_Send_Read(0x07);
SPI_CSN = 1;
SPI_CSN = 0;
//4 byte payload
spi_Send_Read(0x31);
spi_Send_Read(0x04);
SPI_CSN = 1;
SPI_CSN = 0;
//set channel 2
spi_Send_Read(0x25);
spi_Send_Read(0x02);
SPI_CSN = 1;
SPI_CSN = 0;
//set address E7E7E7E7E7
spi_Send_Read(0x30);
for (j = 0; j < 5; j++)
spi_Send_Read(0xE7);
SPI_CSN = 1;
SPI_CSN = 0;
//PWR_UP = 1
spi_Send_Read(0x20);
spi_Send_Read(0x3B);
SPI_CSN = 1;
SPI_CE = 1;
}
void reset_RX(void)
{
unsigned char i, j;
unsigned char buffer[4];
//Read RX payload
SPI_CSN = 0;
spi_Send_Read(0x61);
for (j = 0; j < 4; j++)
{
buffer[j] = spi_Send_Read(0);
}
SPI_CSN = 1;
//Flush RX FIFO
SPI_CSN = 0;
spi_Send_Read(0xE2);
SPI_CSN = 1;
SPI_CSN = 0;
//reset int
spi_Send_Read(0x27);
spi_Send_Read(0x40);
SPI_CSN = 1;
}
unsigned char spi_Send_Read(unsigned char byte)
{
SSPBUF = byte;
while(!DataRdySPI())
;
return SSPBUF;
}
void dly(unsigned int c)
{
INTCONbits.TMR0IF = 0;
WriteTimer0(c);
while (INTCONbits.TMR0IF == 0)
;
}
I changed (used) the SPI function that I made (and worked for communicating between the 2 PICs) and also the "dly" function I removed and used the delays I always use.
I balded the parts that I removed or changed