SparkFun Forums 

Where electronics enthusiasts find answers.

All things pertaining to wireless and RF links
By pleq
#37978
Hi,

I am trying to make 2 x PIC16F689 communicate with each other through 2 x Nordic 2.4GHz Transceiver modules (http://www.sparkfun.com/commerce/produc ... cts_id=151).
Everything runs at 3.3V as I use the same 3.3v voltage regulator to supply both breadboards located a few inches apart.

I used PORTA.2 as an input to set which one is the transmitter and which one is the receiver. The transmitter keeps transmitting every seconds (PORTA.0 connected to a LED is toggled shows transmit activity). The receiver polls the RF_DR1 pin and toggles PORTA.5 (connected to a LED) to show receive activity, when RF_DR1 is active.

My problem is the RF_DR1 pin on the receiver is never active (logic 1), so the LED on PORTA.5 is never toggled. On the transmitter side, the LED on PORTA.0 toggled On/Off, so the it looks like the transmitter code is executed. I have verified the code and connections and everything seems OK, according the the datasheet.

1) Is there a way to make sure the RF transceiver modules are functional ?

2) Have I missed anything in the code below, since I could NOT make these RF transceivers to work... ?

I'd really appreciate any help and suggestions...

Thanks very for your help.
Best regards
pleq
:D


#define RF_24G_DR1 PORTC.F0
#define RF_24G_CLK1 PORTC.F1
#define RF_24G_DATA PORTC.F2
#define RF_24G_CS PORTC.F3
#define RF_24G_CE PORTC.F4

#define RF_24G_DATA_DIR TRISC.F2


////////////////////////////////////////////////////////////////////////////////
//Configuration Bytes
//
//Bytes 14-02: Shockburst Configuration
//Bytes 01-00: General Device Configuration
#define DATA2_W 8

//Byte 13: Length of data payload section RX channel 1 in bits
#define DATA1_W 8

//Byte 12-08: Channel 2 Address
#define ADDR2_4 0x00
#define ADDR2_3 0x00
#define ADDR2_2 0x00
#define ADDR2_1 0x00
#define ADDR2_0 0x00

//Byte 07-03: Channel 1 Address
#define ADDR1_4 0xE7
#define ADDR1_3 0xE7
#define ADDR1_2 0xE7
#define ADDR1_1 0xE7
#define ADDR1_0 0xE7

//Byte 02
// Bit 07-02: ADDR_W - Number of address bits (both RX channels)
// Maximum number of address bits is 40 (5 bytes)
// Bit 01: CRC_L - 8 or 16 bits CRC
// Bit 00: CRC_EN - Enable on-chip CRC generation/checking
// Combine (via |) together constants from each group
// 0b76543210
#define ADDR_W_5_BYTE 0b10100000
#define ADDR_W_4_BYTE 0b10000000
#define ADDR_W_3_BYTE 0b01100000
#define ADDR_W_2_BYTE 0b01000000
#define ADDR_W_1_BYTE 0b00100000

#define CRC_L_8_BIT 0b00000000
#define CRC_L_16_BIT 0b00000010

#define CRC_EN_DISABLE 0b00000000
#define CRC_EN_ENABLE 0b00000001

//Byte 01
// Bit 07: RX2_EN - Enable two channel receive mode
// Bit 06: CM - Communication mode ( Direct or ShockBurst)
// Bit 05: RFDR_SB - RF data rate (1Mbps requires 16MHz crystal)
// Bit 04-02: XO_F - Crystal frequency (Factory default 16MHz crystal mounted)
// Bit 01-00: RF_PWR - RF output power
// Combine (via |) together constants from each group
// 0b76543210
#define RX2_EN_DISABLE 0b00000000
#define RX2_EN_ENABLE 0b10000000

#define CM_DIRECT 0b00000000
#define CM_SHOCKBURST 0b01000000

#define RFDR_SB_250_KBPS 0b00000000
#define RFDR_SB_1_MBPS 0b00100000

#define XO_F_4MHZ 0b00000000
#define XO_F_8MHZ 0b00000100
#define XO_F_12MHZ 0b00001100
#define XO_F_16MHZ 0b00001100
#define XO_F_20MHZ 0b00010000

#define RF_PWR_N20DB 0b00000000 // -20db
#define RF_PWR_N10DB 0b00000001 // -10db
#define RF_PWR_N5DB 0b00000010 // -5db
#define RF_PWR_0DB 0b00000011 // 0db (Full Power)

//Byte 01
// Bit 07-01: RF_CH# - Frequency channel (2400MHz + RF_CH# * 1.0MHz)
// Bit 00: RXEN - RX or TX operation
// Combine (via |) together constants from each group
// 0b76543210
#define RF_CH 0b10000000 // 64 - 2464GHz

#define RXEN_TX 0b00000000
#define RXEN_RX 0b00000001
////////////////////////////////////////////////////////////////////////////////

#define BUF_MAX 1

#define CSDELAY() Delay_us(100)
#define CEDELAY() Delay_us(100)
#define TTADELAY() Delay_us(300)
#define PWUPDELAY() Delay_ms(3)


void RF_24G_initPorts(void)
{
OSCCON = 0x71; // Internal 8Mhz, OSTS = 0, SCS = 1
OPTION_REG = 0xC0; // Disable PORTA/PORTB pull-ups, INTEDG = 1

ANSEL = 0; //Turn pins to Digital instead of Analog
ANSELH = 0; //Turn pins to Digital instead of Analog

PORTA = 0;
TRISA = 0x08; //0 = Output, 1 = Input; RA3 is ALWAYS input on 16F687/689/690
WPUA = 0; // Disable Pull-ups
IOCA = 0; // Disable Interrupt-On-Change on PORTA

PORTB = 0;
TRISB = 0x20; //0 = Output, 1 = Input (RX is an input)
WPUB = 0; // Disable Pull-ups
IOCB = 0; // Disable Interrupt-On-Change on PORTB

PORTC = 0;
TRISC = 0x01; //0 = Output, 1 = Input (DR1 is input)
}

void putByte( char b )
{
//MSB bit first
int i;

RF_24G_DATA_DIR = 0; // Set DATA pin output
RF_24G_CLK1 = 0;
for (i = 0; i < 8; i++)
{
RF_24G_DATA = b.F7;
RF_24G_CLK1 = 1; // Clock out on rising edge
RF_24G_CLK1 = 0;
b <<= 1;
}
}


char getByte(void)
{
//MSB bit first
int i;
char b = 0;

RF_24G_DATA_DIR = 1; // Set DATA pin input
RF_24G_CLK1 = 0;
for (i = 0; i < 8; i++)
{
b <<= 1;
RF_24G_CLK1 = 1;
b.F0 = RF_24G_DATA;
RF_24G_CLK1 = 0; // Read before falling edge
}

return b;
}


void RF_24G_Config(void)
{
RF_24G_DATA_DIR = 0; // Set DATA pin output

RF_24G_CE = 0;
RF_24G_CS = 0;

PWUPDELAY();

RF_24G_CS = 1;
CSDELAY();

//MSB byte first
putByte(DATA2_W);
putByte(DATA1_W);
putByte(ADDR2_4);
putByte(ADDR2_3);
putByte(ADDR2_2);
putByte(ADDR2_1);
putByte(ADDR2_0);
putByte(ADDR1_4);
putByte(ADDR1_3);
putByte(ADDR1_2);
putByte(ADDR1_1);
putByte(ADDR1_0);
putByte(ADDR_W_5_BYTE |
CRC_L_16_BIT |
CRC_EN_ENABLE);
putByte(RX2_EN_DISABLE |
CM_SHOCKBURST |
RFDR_SB_1_MBPS |
XO_F_16MHZ |
RF_PWR_0DB);
putByte(RF_CH | RXEN_RX);

RF_24G_CS = 0;
RF_24G_CE = 1;
}


void RF_24G_SetTxByte(void)
{
RF_24G_DATA_DIR = 0; // Set DATA pin output

RF_24G_CE = 0;
RF_24G_CS = 1;
CSDELAY();

putByte(RF_CH | RXEN_TX);

RF_24G_CS = 0;
RF_24G_CE = 0;
}


void RF_24G_SetTx(void)
{
RF_24G_DATA_DIR = 0; // Set DATA pin output

// Once the wanted protocol, modus and RF channel are set,
// only one bit (RXEN) is shifted in to switch between RX and TX.
RF_24G_CE = 0;
RF_24G_CS = 1;
CSDELAY();

RF_24G_DATA = 0; // 0 for TX; 1 for RX;
RF_24G_CLK1 = 1; // Clock out on rising edge
RF_24G_CLK1 = 0;

RF_24G_CS = 0;
RF_24G_CE = 0;
}


void RF_24G_SetRxByte(void)
{
RF_24G_DATA_DIR = 0; // Set DATA pin output

RF_24G_CE = 0;
RF_24G_CS = 1;
CSDELAY();

putByte(RF_CH | RXEN_RX);
RF_24G_CS = 0;
RF_24G_CE = 1;

RF_24G_DATA_DIR = 1; // Set DATA pin input
}


void RF_24G_SetRx(void)
{
RF_24G_DATA_DIR = 0; // Set DATA pin output

// Once the wanted protocol, modus and RF channel are set,
// only one bit (RXEN) is shifted in to switch between RX and TX.
RF_24G_CE = 0;
RF_24G_CS = 1;
CSDELAY();

RF_24G_DATA = 1; // 0 for TX; 1 for RX;
RF_24G_CLK1 = 1; // Clock out on rising edge
RF_24G_CLK1 = 0;
RF_24G_CS = 0;
RF_24G_CE = 1;

RF_24G_DATA_DIR = 1; // Set DATA pin input
}


void putBuffer(char *pbuf)
{
int i;

RF_24G_DATA_DIR = 0; // Set DATA pin output

RF_24G_CE = 1;
CEDELAY();

putByte(ADDR1_4);
putByte(ADDR1_3);
putByte(ADDR1_2);
putByte(ADDR1_1);
putByte(ADDR1_0);

for (i = 0; i < BUF_MAX; i++)
{
putByte(pbuf);
}
RF_24G_CE = 0;

TTADELAY(); // Time To Air data
}


void getBuffer(char *pbuf)
{
int i;

RF_24G_DATA_DIR = 1; // Set DATA pin input

for (i = 0; i < BUF_MAX; i++)
{
pbuf = getByte();
}
RF_24G_CE = 1;
}


/////////////////////////////////////////////////////////////////////

char TxBuf[BUF_MAX];
char RxBuf[BUF_MAX];

long counter = 0;

void main()
{
unsigned char i;

TxBuf[0] = 'A';
RxBuf[0] = '?';

RF_24G_initPorts();

TRISA.F2 = 1; // Set RA<2> as input for debug
TRISB.F5 = 1; // RB<5> UART RX as input

RF_24G_Config();

if (PORTA.F2)
RF_24G_SetTx(); // Switch to transmit
else
RF_24G_SetRx(); // Switch to receive

PORTA.F0 = 1; // Set LED on PORTA.F0 for debug purpose
PORTA.F5 = 1; // Set LED on PORTA.F5 for debug purpose
Delay_ms(1000);
PORTA.F0 = 0;
PORTA.F5 = 0;

while (1)
{
if (PORTA.F2) // Transmitter
{
if (RF_24G_DATA_DIR)
{
RF_24G_SetTx(); // switch to transmit
Delay_ms(1);
}

if (counter >= 100000)
{
counter = 0;

// Transmit RF
putBuffer(TxBuf); // send packet (buf)

PORTA.F0 = !PORTA.F0;
Delay_ms(1);
}

counter++;
}
else // Receiver
{
if (!RF_24G_DATA_DIR)
{
RF_24G_SetRx(); // switch to receive
Delay_ms(1);
}

if (RF_24G_DR1)
{
getBuffer(RxBuf); // Get packet

// if (RxBuf[0] == 'A')
PORTA.F5 = !PORTA.F5;
}
}

}
}
By DarioG
#38543
I too did struggle with them, at the beginning; afterwards, they proved to be quite good!

Provided the your bit-output routines are good, I can say that I had troubles in delays from CS to CE etc., I mean, every time "state" needs changing.

You can try removing checksum, it's a method of seeing if your module responds to your init sequence: the DATA OUTPUT pin will start outputting a lot of garbage.
By pleq
#38545
Thanks DarioG for your suggestions.
I'll try that next time I have a chance. In the meantime, I am trying to make a better connector for these modules to make sure this is not due some flaky connections.

Also what was your setup ?
Did you use C code on a PIC to interface these module ?
By DarioG
#38552
Yes, C and software "pseudoSPI" as everybody :)
On 18F2620, 2520, 1320
By pleq
#39230
Hi DarioG,
I followed your suggestions and disable the CRC and using only 1 address byte. the Receiver pickep up garbage, as expected. Then I re-enabled the CRC. The receiver picked up less garbage, but still receive only garbage data. It even received garbage when I stopped the transmitter.
By increasing the number of address bytes and CRC bits, the garbage was screened out, but still NO real data was received. Both modules are on 2 separate breadboard, a few inches apart.

Did you run into similar issue when experiencing with these nRF2401A modules ?

Thanks
pleq
By orin
#39235
See my post entitled: "24g_232demo_V02.c ported to BoostC" for some working nRF2401 code. Pay particular attention to the delays. Also see my other post about switching from RX mode to config mode.

Orin.
By pleq
#39342
Thanks for your suggestions and help.

I found out that one of the nRF2401A module (the one used as the transmitter) might be dead. When I set it as a receiver, it did not even receive the garbage data the mother module (previously set as the receiver) received. So at this moment I need to purchase an other nRF2401A module to continue my tests. I'll keep you posted on my tests once I get an other nRF2401A module.

I really appreciate your support.
Thanks
pleq
By pleq
#39724
Hi guys,

I finally received the new nRF2401A modules.
I was able to send and receive data. Youpi!!!.
Thank you very much guys for your help.

One thing is still not clear to me yet.
When the Transmitter sends 3 packets in a row, the Receiver only receives 2 of them. The third one is lost.

It works well if I added a delay of a few hundred micro seconds between the packets sent on the Transmitter side. By packets, I meant (2-byte address + 1-byte data + 2-byte CRC) in 1 Mbps Shockburst mode. Also after pulling CE=0, for each packet, I added a 195us delay + 300us Toa (which should be long enough for sending a 5-bytes packet).

The few hundred micro seconds delay I was talking earlier is in addition to the Toa delay

Does anyone have any idea what happened ?

Thanks
pleq[
By orin
#39727
pleq wrote:Hi guys,

I finally received the new nRF2401A modules.
I was able to send and receive data. Youpi!!!.
Thank you very much guys for your help.

One thing is still not clear to me yet.
When the Transmitter sends 3 packets in a row, the Receiver only receives 2 of them. The third one is lost.

It works well if I added a delay of a few hundred micro seconds between the packets sent on the Transmitter side. By packets, I meant (2-byte address + 1-byte data + 2-byte CRC) in 1 Mbps Shockburst mode. Also after pulling CE=0, for each packet, I added a 195us delay + 300us Toa (which should be long enough for sending a 5-bytes packet).

The few hundred micro seconds delay I was talking earlier is in addition to the Toa delay

Does anyone have any idea what happened ?

Thanks
pleq[
Are you adding the delay between all packets or just between #2 and #3?

I wonder what the delay is between the end of a packet arriving and DR1 being raised.

I've been trying to measure the round trip time - send a packet - the receiver turns around and sends a packet back - receive the returned packet. I'm at about 1600 uS including processing delays at the receive end sending the 'standard' 8 bit address, 4 bytes data, 2 bytes CRC at 250 kbps. To do any better, I'll need to run the PIC faster or use hardware SPI as the C PIC code can take quite a while to clock packets out of the chip!

I've got a reliable protocol (based on Tannenbaum's protocol 4 with a 3-way handshake to start) running on the Sparkfun boards. I'll release it under GPL once I'm happy with it.

Orin.

PS: 2 byte CRC is NOT sufficient to ensure the integrity of your packets! I've added a single byte XOR checksum to my packets and that seems to be catching the bad packets that the CRC was letting through.
By pleq
#39747
Hi orin,

In order to receive all the 3 packets, I added a delay of few hundred (~500us or 1ms) between each packets that were sent out. I did not try to fine tune that delay. I found it very strange as this is on top of the Toa delay. I just could not explain why this delay is needed and mostly why this delay can be omitted if I only sent 2 consecutive packets. However if I send a 3rd packet (without any delay) then it's lost !

As for the 1600us roundtrip latency, I am under the impression that the PIC clock is not the bottle neck. I think it's time required to switch back and forth from transmit to receive mode that is the bottle neck. In my case, a total of 5 bytes needs to clock into the module and only one byte out of the module. Running at 8Mhz, that's 0.5us per instruction. Even in C, with 10 instructions to shift a bit, that only costs 40us/byte out of the 1600us.

pleq
By pleq
#39749
Oh, one more thing...
How would you determine the baud rate (bps) when using these nRF2401A modules ? With the delay needed between consecutive packets, I doubt it could reach even half of the 1Mbps mentioned in the spec...
By orin
#39758
pleq wrote:Hi orin,

In order to receive all the 3 packets, I added a delay of few hundred (~500us or 1ms) between each packets that were sent out. I did not try to fine tune that delay. I found it very strange as this is on top of the Toa delay. I just could not explain why this delay is needed and mostly why this delay can be omitted if I only sent 2 consecutive packets. However if I send a 3rd packet (without any delay) then it's lost !

As for the 1600us roundtrip latency, I am under the impression that the PIC clock is not the bottle neck. I think it's time required to switch back and forth from transmit to receive mode that is the bottle neck. In my case, a total of 5 bytes needs to clock into the module and only one byte out of the module. Running at 8Mhz, that's 0.5us per instruction. Even in C, with 10 instructions to shift a bit, that only costs 40us/byte out of the 1600us.

pleq
Well, my 1600 uS does include time to check my checksum at the receive end, extract data from the incoming packet, fill set the Ack bit in the packet to be returned, calculate a checksum on the Ack packet and switch from RX to TX. I am running at 250kbps as well.

This can be improved by sending the return packet then extracting the incoming data during the 195+Toa uS. I need to do some timings on the receive side - detecting DR1 to CE = 0 sending the Ack. The 1600 uS is from CE = 0 sending a packet to DR1 receiving the Ack.

Orin.
By pleq
#39799
Hi orin,

Could you try sending more than 2 consecutive packets and see if you experienced the same problem I have ?

In your handshaking scheme, do you send one packet and wait for the ACK before sending an other one or do you use a sliding window (sending multiple packets and wait for ACKs) ?

Thanks
pleq