SparkFun Forums 

Where electronics enthusiasts find answers.

All things pertaining to wireless and RF links
By frank26080115
#44447
I can't get a packet from one radio to another, but the first problem I noticed is that I don't think the primary Tx radio isn't even trying to transmit anything.

It is powered up, everything is initialized according to the datasheet, it is put in primary Tx mode. the interrupts on IRQ are enabled. auto-retransmit is enabled and it's set to 15 retries before MAX_RT should trip. I am constantly toggling the CE pin after I load the TX_PAYLOAD. Interrupt is detected by polling (pin set to input with internal pullups), during the while loop, CE is constantly being toggled for 500us at a time.

The primary Rx device isn't powered on, so why isn't MAX_RT causing an interrupt?

Status register says FIFO is full even though the first transmission never completed

Also I run a flush command in my init code, but it appears after 3 resets, status register says FIFO is full, while a power-on reset will empty the FIFO

OBSERVE_TX is never changed, and also CD is 0

I have auto ack enabled

what the hell am I doing wrong? I've followed the datasheet word for word...
Last edited by frank26080115 on Mon Mar 10, 2008 12:41 pm, edited 2 times in total.
By brennen
#44450
Have you verified the actual values that you are sending to the nRF24L01's configuration registers? If not, you need to print those out some way so that you can verify them. If you need example code, go to my website (see the signature below). I have a bunch of tutorials and information on the 24L01 that should help to get you started.

My initial suggestion is that you first start out by sending packets without using any of the auto-ack features enabled, and then build off that code when it works.
By frank26080115
#44452
well what about my issue with flushing the FIFO buffer? I'm am certain that my SPI is working correctly because I can write and read from registers just fine, they return the values I've written to them.
By brennen
#44453
I am not sure by how you have your first post worded, but are you getting any interrupts whatsoever after you send a packet (TX_DS or MAX_RT)? If not, you obviously don't have something configured properly. Make sure that you have the PWR_UP bit set, the PRIM_RX bit cleared, and all the interrupts are enabled. As I suggested before, turn auto-ack off (just for now). Just try to simply send a packet. You should be able to get the TX_DS interrupt regardless of whether or not there is a receiver or not since auto-ack will be off. This will test whether you are setting the TX device to the proper settings and you are operating the CE pin properly. If you can get that going, then try using auto-ack.

Life is much easier if you take things one step at a time. :D
By frank26080115
#44552
I've read your tutorial and code, I've simplified it down to this (AVR GCC, ATMEGA644 at 18.432MHz):
Code: Select all
#define norChannel 2

//#define norSerDebug

// CS pin
#define csPort PORTB // output port register
#define csDDR DDRB // direction register, 1 = output
#define csPin 1 // pin number

// CE pin
#define cePort PORTB
#define ceDDR DDRB
#define cePin 0

//INT pin
#define intPort PORTB
#define intDDR DDRB
#define intPinIn PINB // port input register
#define intPin 2

#define packetLength 14 // payload width
uint8_t norOutBuffer[packetLength]; // inbox
uint8_t norInBuffer[packetLength]; // outbox

volatile uint8_t norBoolean; // flags
#define TxDone 0
#define TxFailed 1
#define RxDone 3

void norSel()
{
	// select by clearing CSN pin
	cbi(csPort, csPin);
}

void norDesel()
{
	// deselect by setting CSN pin
	sbi(csPort, csPin);
}

void norWR(uint8_t reg, uint8_t data)
{
	// write register
	norSel(); // CSN pin
	spiSend(0b00100000 | reg); // write register command
	spiSend(data); // put in data
	norDesel(); // CSN pin
}

uint8_t norRR(uint8_t reg)
{
	uint8_t temp;
	// read register
	norSel(); // CSN pin
	spiSend(0b00000000 | reg); // register read command
	spiSend(0);
	norDesel(); // CSN pin
	temp = spiRead(); // register data here
	return temp;
}

void norCE(uint8_t data)
{
	// change CE pin state
	if(data == 0)
	{
		cbi(cePort, cePin);
	}
	else
	{
		sbi(cePort, cePin);
	}
}

void norFlushTx()
{
	norSel();
	spiSend(0b11100001); // flush Tx FIFO command
	norDesel();
}

void norFlushRx()
{
	norSel();
	spiSend(0b11100010); // flush Rx FIFO command
	norDesel();
}

void norRxMode()
{
	norWR(0x00, 0b00001011); // IRQ on, AA on, CRC 1, PRX
	norCE(1);
}

void norTxMode()
{
	norWR(0x00, 0b00001010); // IRQ on, AA on, CRC 1, PTX
	norCE(0);
}

void norInit(uint8_t mode)
{
	norBoolean = 0; // clear flags

	// setup pins

	// chip select pin
	sbi(csPort, csPin);
	sbi(csDDR, csPin);

	// chip enable pin
	cbi(cePort, cePin);
	sbi(ceDDR, cePin);

	// IRQ pin input
	cbi(intPort, intPin);
	cbi(intDDR, intPin);

	spiInit(); // initialize SPI, 18.432MHz div 4, mode 00
	
	// reset FIFOs
	norFlushTx();
	norFlushRx();

	// minimal config with AA
	
	norWR(0x01, 0b00000001); // enable AA on pipe 0

	norWR(0x05, norChannel); // setup channel

	norWR(0x11, packetLength); // pipe 0 payload width

	// power up in different modes
	if(mode == 1)
	{
		norRxMode();
	}
	else
	{
		norTxMode();
	}

	_delay_us(1500); // delay for power up
}

void norReadStatus()
{
	norSel();
	spiSend(255); // Send NOP to check STATUS
	uint8_t norStatusVar = spiRead(); // read status
	norDesel();

	norWR(0x07, norStatusVar & 0b01110000); // clear interrupts

	if(bit_is_set(norStatusVar, 6))
	{
		// New Packet Received
		sbi(norBoolean, RxDone);
	}

	if(bit_is_set(norStatusVar, 5))
	{
		// Tx Complete
		sbi(norBoolean, TxDone);
	}

	if(bit_is_set(norStatusVar, 4))
	{
		// Max Retry Reached, Tx Failed
		sbi(norBoolean, TxFailed);
	}
}

void norLoadTx()
{
	// load the Tx Payload
	norSel();
	spiSend(0b10100000); // W_TX_PAYLOAD command
	uint8_t i;
	for(i = 0; i < packetLength; i++)
	{
		// load into FIFO
		spiSend(norOutBuffer[i]);
	}
	norDesel();
}

void norLoadRx()
{
	// read the Rx Payload
	norSel();
	spiSend(0b01100001); // R_RX_PAYLOAD command
	uint8_t i;
	for(i = 0; i < packetLength; i++)
	{
		// read from FIFO
		spiSend(0);
		norInBuffer[i] = spiRead();
	}
	norDesel();
}

void norTx()
{
	norTxMode(); // PTX mode

	norLoadTx(); // put the payload into FIFO

	norBoolean = 0; // clear flags

	norCE(1); // toggle CE
	_delay_us(11);
	norCE(0);

	// wait for either finish or failure
	while(bit_is_clear(norBoolean, TxDone) && bit_is_clear(norBoolean, TxFailed))
	{
		while(bit_is_set(intPinIn, intPin)); // poll interrupt pin

		norReadStatus(); // read status
	}

	if(bit_is_set(norBoolean, TxDone)) // if finished
	{
		while(bit_is_clear(norBoolean, RxDone)) // wait for finish
		{
			while(bit_is_set(intPinIn, intPin)); // poll interrupt pin

			norReadStatus(); // read status
		}

		norLoadRx(); // read the Rx payload
	}
	else if(bit_is_set(norBoolean, TxFailed))
	{
		norFlushTx(); // if failed, flush FIFO
	}
}

void norRx()
{
	norLoadTx(); // load reply payload into FIFO

	norBoolean = 0; // clear flags

	norRxMode(); // PRX mode, CE on

	while(bit_is_clear(norBoolean, TxDone)) // wait for finish
	{
		while(bit_is_set(intPinIn, intPin)); // poll interrupt pin

		norReadStatus(); // read status
	}

	norLoadRx(); // read FIFO
}
The Rx device is on, and waiting, but the Tx still never gets the interrupt.

I have previously been able to send packets without autoack, not with that code though, that was done on a single processor with both radios on one SPI bus.

EDIT:
Wow, I went back to my old code, enhanced shockburst works!
The difference is that CE is tied to VCC... I wonder what's wrong with my microcontroller pin, my logic probe is telling me that even if I set it to 1, CE pin is pulsing. It's the PB0 on an atmega644, datasheet says it's also a clock souce for USRT or a timer/counter0 souce, but neither of those are supposed to be on

I don't know what happened, but it works on an atmega168 but not 644... seems to be an issue reading data from the radio, MISO is returning 0s all the time...