Hello,
I working on interfacing NRF24L01+ with PIC16f684(without hardware SPI). As this PIC don' got hardware SPI so I need to use Software SPI.I am using MikroC pro for PIC and it got software SPI library too. But its not working and PIC is not able to communicate with NRF. I think this is a RMW issue as software SPI is using I/O ports and I/O ports got RMW problem, as it worked once and now its not working. And MikroC don't share the source of their library so I cannot modify it to work using shadow registers. Please review my code:
I working on interfacing NRF24L01+ with PIC16f684(without hardware SPI). As this PIC don' got hardware SPI so I need to use Software SPI.I am using MikroC pro for PIC and it got software SPI library too. But its not working and PIC is not able to communicate with NRF. I think this is a RMW issue as software SPI is using I/O ports and I/O ports got RMW problem, as it worked once and now its not working. And MikroC don't share the source of their library so I cannot modify it to work using shadow registers. Please review my code:
Code:
#define TX_mode // define TX_mode or RX_mode
//#define chn 83
#include "nRF24L01.h"
const char IGM[]="I";
//const char IGN[]="N";
const char SDD[] ="S";
const char RTH[]="R";
// Pipe Addresses
// adr0 should be unique
// Bytes are arranged lowest to highest
const char adr0[] = {0x78,0x78,0x78,0x78,0x78}; // LSB first
char Data_Out[21], stat;
short dataLength = 20;
char j;
bit DS;
char txt[11];
// Software SPI module connections
sbit SoftSpi_SDI at SDI;
sbit SoftSpi_SDO at SDO;
sbit SoftSpi_CLK at RC3_bit;
sbit SoftSpi_SDI_Direction at TRISC4_bit;
sbit SoftSpi_SDO_Direction at TRISC2_bit;
sbit SoftSpi_CLK_Direction at TRISC3_bit;
// End Software SPI module connections
// You can change these pins as long as your microcontroller supports SPI on the required pins
sbit Irq_pin at PORTC.B0; sfr;
sbit Mosi_pin at PORTC.B2; sfr;
sbit Ce_pin at PORTC.B1; sfr;
sbit Sclk_pin at PORTC.B3; sfr;
sbit Csn_pin at PORTC.B5; sfr;
//sbit Miso_pin at PORTC.B4; sfr;
sbit Irq_tris at TRISC.B0; sfr;
sbit Mosi_tris at TRISC.B5; sfr;
sbit Ce_tris at TRISC.B1; sfr;
sbit Sclk_tris at TRISC.B3; sfr;
sbit Csn_tris at TRISC.B2; sfr;
sbit Miso_tris at TRISC.B4; sfr;
//declarations of IO devices
sbit NRF at RC0_bit;//NRF power bit
sbit ACK at RA2_bit;// ACK LED to indicate ACK receieved from PRX
bit IGNM ;
bit SD ;
bit HT ;
bit DTS;
// I use a procedure for any delay that is used more than once
void Comm_Delay() {Delay_us(10);} // You can experiment with this delay
void Delay_10() {Delay_ms(10);}
void Delay_100() {Delay_ms(100);}
void Delay_500() {Delay_ms(500);}
void Clear_Data(char dat[])
{
char i;
for(i=0;i<dataLength;i++)dat[i] = ' ';
}
void toggleCSN()
{
Csn_pin = 1;
Delay_us(20); // You can experiment with this delay
Csn_pin = 0;
Comm_Delay();
}
char Get_Status()
{
char s;
Ce_pin = 0;
toggleCSN();
Soft_SPI_Write(STATUS);
Comm_Delay();
s = Soft_SPI_Read(NOP);
Comm_Delay();
Csn_pin = 1;
return s;
}
char *getConst(char dest[], const char source[])
{
int i = 0;
while (source[i]) // while (source[i] != '\0')
{dest[i] = source[i]; i++;}
dest[i] = '\0';
return dest;
}
char Get_FIFO_Flags()
{
char s;
Ce_pin = 0;
toggleCSN();
Soft_SPI_Write(FIFO_STATUS);
Comm_Delay();
s = Soft_SPI_Read(NOP);
Comm_Delay();
Csn_pin = 1;
return s;
}
void sendBuffer()
{
char i;
do{
toggleCSN();
Soft_SPI_Write(STATUS | W_REGISTER);
Comm_Delay();
Soft_SPI_Write(0xff); //clear flags
Comm_Delay();
toggleCSN();
Soft_SPI_Write(FLUSH_TX);
Comm_Delay();
toggleCSN();
Soft_SPI_Write(W_TX_PAYLOAD);
for(i = 0; i < dataLength; i++) {Comm_Delay(); Soft_SPI_Write(Data_Out[i]);}
Comm_Delay();
Csn_pin = 1;
Ce_pin = 1;
Delay_10();
j = (Get_Status() & 0x20); // keep trying until ack is received
}while(j==0);
ACK=0;//ACK receieved from PRX and hence ACK LED is lit
}
char init_Radio()
{
char i;
Ce_pin = 0; // must be in standby or power down to write
Comm_Delay();
toggleCSN();
Soft_SPI_Write(CONFIG | W_REGISTER);
Comm_Delay();
#ifdef TX_mode
Soft_SPI_Write(PWR_UP+ CRCO + EN_CRC); // Transmitter
Comm_Delay();
toggleCSN();
Soft_SPI_Write(EN_AA | W_REGISTER);
Comm_Delay();
Soft_SPI_Write(ENAA_P0);
Comm_Delay();
toggleCSN();
Soft_SPI_Write(EN_RXADDR | W_REGISTER);
Comm_Delay();
Soft_SPI_Write(ERX_P0);
Comm_Delay();
toggleCSN();
Soft_SPI_Write(RX_ADDR_P0 | W_REGISTER);
for(i=0;i<5;i++){Comm_Delay(); Soft_SPI_Write(adr0[i]);} // This is the pipe in use by this transmitter
Comm_Delay();
// The addresses above and below must be the same
toggleCSN(); // Choose any of the 6 addresses used by the receiver
Soft_SPI_Write(TX_ADDR | W_REGISTER);
for(i=0;i<5;i++){Comm_Delay(); Soft_SPI_Write(adr0[i]);} // This is the pipe in use by this transmitter
Comm_Delay();
#endif
toggleCSN();
Soft_SPI_Write(SETUP_AW | W_REGISTER);
Comm_Delay();
Soft_SPI_Write(AW5);
Comm_Delay();
toggleCSN();
Soft_SPI_Write(SETUP_RETR | W_REGISTER);
Comm_Delay();
Soft_SPI_Write(0xfaf);
Comm_Delay();
toggleCSN();
Soft_SPI_Write(RF_CH | W_REGISTER);
Comm_Delay();
Soft_SPI_Write(83); // Set your channel here. Obviously it must be the same for TX and RX.
Comm_Delay();
toggleCSN();
Soft_SPI_Write(RF_SETUP | W_REGISTER);
Comm_Delay();
Soft_SPI_Write(RF_PWR +RF_DR_LOW );
Comm_Delay();
toggleCSN();
Soft_SPI_Write(RX_PW_P0 | W_REGISTER);
Comm_Delay();
Soft_SPI_Write(dataLength);
Comm_Delay();
Csn_pin = 1;
i = Get_Status();
return i;
}
// =============================================================================
// =============================================================================
void main(){
ADCON0=0x00;
ADCON1 = 0x00; // digital not analog
ANSEL=0;
CMCON0=0x07;
//TRISC.B5=0;//MOSI
//TRISC.B3=0;//SCLK
//TRISC.B4=1;//MISO
TRISC.B1=0;//CE
TRISC.B2=0;//CSN
TRISC.B0=0;//NRF power bit
TRISA =0b00001011;
Csn_tris = 0;
Csn_pin = 1;
Ce_tris = 0;
Ce_pin = 0; // 1 = listen or transmit
DTS=1;
Clear_Data(Data_Out);
NRF=1; //NRF is off
DS=0;
ACK=0;
IGNM=0;
SD=0;
HT=0;
delay_ms(500);
ACK=1;// firstly ACK will be OFF
do {
if(PORTA.RA3==1) //Ignore mode button
{
IGNM=1;
//DTS=1;
}
if(PORTA.RA0==1) // Do not ignore mode button
{
SD=1;
// DTS=1;
}
if(PORTA.RA1==1)
{
HT=1;
}
if(IGNM==1&&DTS==1) // if ignore button is pressed and data is to be send
{
DTS=0;
NRF=0;
CSN_pin=1;
Delay_ms(200);
Soft_SPI_Init();
Delay_ms(200);
stat = init_Radio();
Clear_Data(Data_Out);
getConst(Data_out,IGM);
// Ce_pin=1;
// Csn_pin=1;
sendBuffer();
delay_ms(1);
Ce_pin=0;
Csn_pin=0;
NRF=1;
IGNM=0;
}
if(SD==1&&DTS==1) // if Silent dialling is pressed
{
DTS=0;
NRF=0;
CSN_pin=1;
Delay_ms(200);
Soft_SPI_Init();
Delay_ms(200);
stat = init_Radio();
Clear_data(Data_out);
getConst(Data_out,SDD);
//Ce_pin=1;
// Csn_pin=1;
sendBuffer();
delay_ms(1);
Ce_pin=0;
Csn_pin=0;
NRF=1;
SD=0;
}
if(HT==1&&DTS==1) // HT start button i pressed
{
DTS=0;
NRF=0;
CSN_pin=1;
Delay_ms(200);
Soft_SPI_Init();
Delay_ms(200);
stat = init_Radio();
Clear_Data(Data_Out);
getConst(Data_out,RTH);
// Ce_pin=1;
// Csn_pin=1;
sendBuffer();
delay_ms(1);
Ce_pin=0;
Csn_pin=0;
NRF=1;
HT=0;
}
}while(1);
}