SparkFun Forums 

Where electronics enthusiasts find answers.

All things pertaining to wireless and RF links
By mchang
#15362
Using PIC 18F2455 right now with LMC6482A and an MOSFET to supply 3V. I "ported" the sparkfun PIC code to C18 and am using the C18 SPI functions from spi.h.

It seems that the RX side only actually receives data from the transmitter if it is sent three (or more) times (sending a 4-byte payload like the SF example). The RX_IRQ goes low on the first transmit, but nothing gets read out of the RX FIFO (but all zeros) unless I wait for the third transmission.

Code can get pasted here if ya'll want it.
By mchang
#15372
Fixed. Seems like the nRF24L01 in ShockBurst RX mode needs you to lower CE to read out of the RX FIFOs. Doesn't seem to be very clear in the data sheet except maybe:
p11: "The MCU can access the FIFOs at any time, in power down mode, in standby modes, and during RF packet transmission."
or
p15: 6. MCU sets the CE pin low to enter Standby-I mode.
7. MCU can clock out the payload data at a suitable rate via the SPI interface.
Not terribly obvious to me, but what do I know :), I just started playing with these.
By jimlake
#15374
Welcome to the clunkiest data sheet around. There is a whole lot of stuff that is not in there.
By mchang
#15376
There doesn't seem to be much of a repository of working code for these things. Am I missing something?
By jimlake
#15377
No you are not. I have some C code I will share, but it is all for Atmel AVR and it probably won't work on anything else. I found out the hard way that porting code can be problematic for the RF2401 becaue of timing issues.

Jim Lake
By brennen
#15404
I'm guessing that the post I made about a month ago with .h and .c include files for the nRF24L01 went unnoticed. It implements pretty much every function available on the chip and is very well-commented.
User avatar
By leon_heller
#15405
brennen wrote:I'm guessing that the post I made about a month ago with .h and .c include files for the nRF24L01 went unnoticed. It implements pretty much every function available on the chip and is very well-commented.
I downloaded it and tried compiling it, but some header files were missing. What compiler did you use?

Leon
By brennen
#15408
I used the 4.1 version of GCC that came with the newer version of WinARM to compile. Upon re-inspecting the code today, I noticed that in nrf24l01.c, you can take out the "<include> lcd.h" line since that code isn't used (I was testing the code using an LCD to spit values out and forgot to remove the include).

As far as nrf24l01.h, lines 44-46 must be changed for your own personal chip. CE_IOREGISTER must be defined as whatever register on your microcontroller that handles the actual pin output for your CE pin. CE_PINMASK is the mask that is used to clear and set this pin within CE_IOREGISTER. Since I'm using the LPC2148, I have included the file lpc214x.h since it contains the definitions for the registers I'm defining.

For example, my project is using pin P0.21 on my microcontroller to control the CE pin on the nRF24L01. Hence, register FIO0PIN controls that pins on or off status, and that is why I have the statement "#define CE_IOREGISTER FIO0PIN". Also, the mask for pin 21 is 0x200000 (this is a 32 bit register), which is the reason for the statement "#define CE_PINMASK 0x200000".

The last thing you have to do yourself is provide the function "void spi1_send(unsigned char * data, unsigned int len)". The purpose of this function is to allow you to send an array of characters (unsigned char * data) with a specified length (unsigned int len) while constantly holding CSN low. I had to do this because the LPC2148 wouldn't work properly in any of its automatic modes, so I made the function manually hold CSN low.

Other than that, I can't think of anything else right off hand that you should need. In the case that anyone is using an LPC21xx with an SSP controller on it, I can provide you with my SPI code as well.
User avatar
By leon_heller
#15409
brennen wrote:I used the 4.1 version of GCC that came with the newer version of WinARM to compile. Upon re-inspecting the code today, I noticed that in nrf24l01.c, you can take out the "<include> lcd.h" line since that code isn't used (I was testing the code using an LCD to spit values out and forgot to remove the include).

As far as nrf24l01.h, lines 44-46 must be changed for your own personal chip. CE_IOREGISTER must be defined as whatever register on your microcontroller that handles the actual pin output for your CE pin. CE_PINMASK is the mask that is used to clear and set this pin within CE_IOREGISTER. Since I'm using the LPC2148, I have included the file lpc214x.h since it contains the definitions for the registers I'm defining.

For example, my project is using pin P0.21 on my microcontroller to control the CE pin on the nRF24L01. Hence, register FIO0PIN controls that pins on or off status, and that is why I have the statement "#define CE_IOREGISTER FIO0PIN". Also, the mask for pin 21 is 0x200000 (this is a 32 bit register), which is the reason for the statement "#define CE_PINMASK 0x200000".

The last thing you have to do yourself is provide the function "void spi1_send(unsigned char * data, unsigned int len)". The purpose of this function is to allow you to send an array of characters (unsigned char * data) with a specified length (unsigned int len) while constantly holding CSN low. I had to do this because the LPC2148 wouldn't work properly in any of its automatic modes, so I made the function manually hold CSN low.

Other than that, I can't think of anything else right off hand that you should need. In the case that anyone is using an LPC21xx with an SSP controller on it, I can provide you with my SPI code as well.
Thanks. I'm using the CrossWorks tools which are based on gcc. I've just got a bit further with it.

The following routines actually seem to be required: spi1_clear_fifo(), DelayUS(), spi1_send() and spi1_read().

Inserting stubs for them and a dummy main(), the whole thing seems to build OK.

Leon
By mchang
#15410
brennen wrote:I'm guessing that the post I made about a month ago with .h and .c include files for the nRF24L01 went unnoticed. It implements pretty much every function available on the chip and is very well-commented.
I looked at your code. Thanks for posting it. A few more prototypes are needed for spi reads, but otherwise, it seems nicely complete.

However, a quick glance at it yesterday I didn't notice the flipping of the CE pin during RX FIFO read. Of course, it was just a cursory glance, so I may be wrong. Did it work for you without putting the chip out of enable?
By brennen
#15414
As far as I can tell, there are no problems with the read code (I'm using it as I type this message). You do have to be careful about clearing your interrupts and fifos when reading from and writing to the nRF24L01s (this is done automatically in my code).
By mchang
#15415
brennen wrote:As far as I can tell, there are no problems with the read code (I'm using it as I type this message). You do have to be careful about clearing your interrupts and fifos when reading from and writing to the nRF24L01s (this is done automatically in my code).
Hrm. The version of your code does not clear any interrupts during the nrf24l01_read_rx_payload(...) operation. It does clear the spi fifo, which I will look into on my side. Also, I figure you're talking about the code that *uses* your nrf library.

My procedure for RX is:
* CE = 0
* spi send 0x61 (R_RX_PAYLOAD)
* spi read payload
* reset interrupt (0x27)
* flush RX FIFO (0xE2)
* CE = 1

Do you see anything wrong with that? The version of your library (just the RX function) I have is pasted below.

Thanks.
Code: Select all
void nrf24l01_read_rx_payload(unsigned char * data, unsigned int len, bool includestatus)
{
	char buffer[33];
	unsigned int count;
	unsigned int numbytes;
	
	spi1_clear_fifo();
	
	if(includestatus == false)	
		numbytes = len + 1;
	else
		numbytes = len;
	
	buffer[0] = nrf24l01_R_RX_PAYLOAD;

	spi1_send(buffer, numbytes);
	
	for(count = 0; count <= len; count++)
		buffer[count + 1] = data[count];
		
	if(includestatus == false)
		spi1_read();
	
	for(count = 0; count < len; count++)
		data[count] = spi1_read();
}
By brennen
#15420
Looks like you have pointed out a discrepancy in my comments. Instead of calling nrf24l01_clear_flush() in my call to nrf24l01_read_rx_payload() in the library, I actually call it in my main() function in my main.c file. I don't make this call when I transmit at all though, as the TX_DS interrupt apparently clears itself when you write to the TX FIFO again.

As far as CE goes, the only time I make any change to it in my receiver code is in the nrf24l01_initialize() function (you're not supposed to make changes to registers with it high). I can't find anywhere else that changes it at all for the receiver, be it in the library or my other code. The transmitter will toggle CE in order to send the data payload, but, like I said, I don't have to change CE to read from the 24L01 (at least not with the ones I have). YMMV, though.
By mchang
#15421
Thanks for the insight. It may still be a timing problem on my side that is alleviated (slightly) by toggling the CE. I will try messing with my SPI buffer flush now and report back.
By mchang
#15422
ok, update.

my method of turning of CE to read from RX FIFOs seems to work.

brennen's method of clearing the RX_FIFO before reading the payload works as well.

so, i have code that does
1. flush rx fifo
2. read rx payload
3. reset interrupts

and that works fine.

It seems counter-intuitive to me to flush the FIFOs before reading the payload. I thought the payload would already be in the FIFOs? I will revisit the datasheet.

thanks for the help, brennen. I now have code that works and is fairly clean. I didn't end up using your code, but it is definitely a good starting point now that I understand the RX FIFO should be cleared.