I’ve been screwin with a pair of nRF24L01s hooked up to a dev board with an Atmel ATMega16 chip. The board itself has built in SPI support, but I couldn’t get it to work nice so I wrote out my own fuctions for sending/receiving SPI data. Anyways, the problem I’m having is that my nRF24L01 designated as the PRX doesn’t seem to be receiving data. The PTX chip appears to be transmitting as it IS asserting the IRQ pin low and the status register is reflecting the change from a full FIFO to a not full one, as well as showing the interrupt bit set when my transmission is done. The PRX on the other hand just sits there…it doesn’t get anything. I’ve copied the setup of my boards pretty much verbatim from the PIC example code located on SparkFun’s product page for the MiRF v2 (the chips i’m using). Only difference mostly is the masking of interrupts and use of 16-bit CRC insead of 8-bit. Below is the code that I’ve developed in CodeVision AVR and below that is the output that I’m getting on my terminal.
/*****************************************************
This program was produced by the
CodeWizardAVR V1.25.7 beta 5 Professional
Automatic Program Generator
© Copyright 1998-2007 Pavel Haiduc, HP InfoTech s.r.l.
http://www.hpinfotech.com
Project :
Version :
Date : 9/12/2007
Author : ****
Company : ****
Comments:
Chip type : ATmega16
Program type : Application
Clock frequency : 6.000000 MHz
Memory model : Small
External SRAM size : 0
Data Stack size : 256
*****************************************************/
#include <mega16.h> //We need that ATMega16 library goodness
#include <delay.h> //Used for delay_ms();
#include <stdio.h> //We like printf dont we?
#include <spi.h> //SPI functions (not used yet)
#include <math.h> //Power function needed
#define TX_CSN PORTB.4
#define RX_CSN PORTB.3
#define SCK PORTB.7
#define MISO PINB.6
#define MOSI PORTB.5
#define TX_CE PORTB.2
#define RX_CE PORTB.1
int ptx_spitalk(int);
int prx_spitalk(int);
void enable_ptx(void);
void disable_ptx(void);
void enable_prx(void);
void disable_prx(void);
//Debugging functions
void showregisters_ptx(void);
void showregisters_ptx_macro(int);
void showregisters_prx(void);
void showregisters_prx_macro(int);
void config_ptx(void);
void config_prx(void);
void main(void)
{
// Declare your local variables here
int temp0, i;
// Input/Output Ports initialization
// Port A initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
// State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T
PORTA=0x00;
DDRA=0x00;
// Port B initialization
// Func7=Out Func6=In Func5=Out Func4=Out Func3=Out Func2=Out Func1=Out Func0=In
// State7=0 State6=T State5=0 State4=0 State3=0 State2=0 State1=0 State0=T
PORTB=0x00;
DDRB=0xBE;
// Port C initialization
// All pins output
// State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T
PORTC=0xFF;
DDRC=0xFF;
// Port D initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
// State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T
PORTD=0x00;
DDRD=0x00;
// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: Timer 0 Stopped
// Mode: Normal top=FFh
// OC0 output: Disconnected
TCCR0=0x00;
TCNT0=0x00;
OCR0=0x00;
// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: Timer 1 Stopped
// Mode: Normal top=FFFFh
// OC1A output: Discon.
// OC1B output: Discon.
// Noise Canceler: Off
// Input Capture on Falling Edge
// Timer 1 Overflow Interrupt: Off
// Input Capture Interrupt: Off
// Compare A Match Interrupt: Off
// Compare B Match Interrupt: Off
TCCR1A=0x00;
TCCR1B=0x00;
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x00;
OCR1AL=0x00;
OCR1BH=0x00;
OCR1BL=0x00;
// Timer/Counter 2 initialization
// Clock source: System Clock
// Clock value: Timer 2 Stopped
// Mode: Normal top=FFh
// OC2 output: Disconnected
ASSR=0x00;
TCCR2=0x00;
TCNT2=0x00;
OCR2=0x00;
// External Interrupt(s) initialization
// INT0: On
// INT0 Mode: Falling Edge
// INT1: On
// INT1 Mode: Falling Edge
// INT2: Off
GICR|=0xC0;
MCUCR=0x0A;
MCUCSR=0x00;
GIFR=0xC0;
// Timer(s)/Counter(s) Interrupt(s) initialization
TIMSK=0x00;
// Analog Comparator initialization
// Analog Comparator: Off
// Analog Comparator Input Capture by Timer/Counter 1: Off
ACSR=0x80;
SFIOR=0x00;
// SPI initialization
// SPI Type: Master
// SPI Clock Rate: 46.875 kHz
// SPI Clock Phase: Cycle Start
// SPI Clock Polarity: Low
// SPI Data Order: MSB First
//SPCR=0x53;
//SPSR=0x00;
/*
#asm
in r30,spsr
in r30,spdr
#endasm
*/
//enable global interrupts
#asm("sei")
disable_ptx();
disable_prx();
for(i=0; i<15; i++)
{
//Throw out a message for 15 seconds so we have to time switch COM1 control
//from AVR Bootloader over to the CVAVR terminal
printf("Text display test: [OK] \r");
delay_ms(1000);
}
PORTC = 0xFE; //Debugging lights - Light 1 LED to indicate code start
printf("Setting up PRX/PTX...\r");
config_prx();
config_ptx();
printf("Done setting up PRX/PTX...\r\r");
//Debugging Info
showregisters_ptx();
showregisters_prx();
//test send a packet
enable_ptx();
ptx_spitalk(0xE1);
disable_ptx();
enable_ptx();
ptx_spitalk(0xA0);
ptx_spitalk(0x31);
ptx_spitalk(0x32);
ptx_spitalk(0x33);
ptx_spitalk(0x34);
disable_ptx();
enable_ptx();
ptx_spitalk(0xA0);
ptx_spitalk(0x31);
ptx_spitalk(0x32);
ptx_spitalk(0x33);
ptx_spitalk(0x34);
disable_ptx();
enable_ptx();
ptx_spitalk(0xA0);
ptx_spitalk(0x31);
ptx_spitalk(0x32);
ptx_spitalk(0x33);
ptx_spitalk(0x34);
disable_ptx();
//3 4-byte packets are clocked over SPI so that we can test the FIFO full
//flag in the status register
enable_ptx();
ptx_spitalk(0x07);
temp0 = ptx_spitalk(0x00);
printf("Pre-TX PTX Status Register: %02X\r",temp0); //Print out status register
disable_ptx();
enable_prx();
prx_spitalk(0x07);
temp0 = prx_spitalk(0x00);
printf("Pre-TX PRX Status Register: %02X\r",temp0); //Print out status register
disable_prx();
PORTC = 0x00; //Debugging lights - Light all LEDs to indicate data TX
printf("Data Transmit about to occur!\r");
TX_CE = 1; //activate transmitter
delay_ms(1);
TX_CE = 0; //disable transmitter
delay_ms(2000); //Debugging - can measure the PTX's IRQ line with a
//logic probe, voltmeter, or o-scope to make sure line is low
enable_ptx();
ptx_spitalk(0x07); //Read the status register
temp0 = ptx_spitalk(0x00);
printf("Post-TX PTX Status Register: %02X\r",temp0); //Print out status register
disable_ptx();
enable_ptx();
ptx_spitalk(0x27); //Clear the TX_DS bit in the status register
ptx_spitalk(0x20);
disable_ptx();
enable_ptx();
ptx_spitalk(0x07);
temp0 = ptx_spitalk(0x00);
printf("Post-TX PTX Status Register [INT Cleared]: %02X\r",temp0); //Print out status register
disable_ptx();
//End transmission code...below is receiver code
enable_prx();
prx_spitalk(0x61);
temp0 = prx_spitalk(0x00);
printf("Result: %02X\r",temp0); //Print out received data
temp0 = prx_spitalk(0x00);
printf("Result: %02X\r",temp0); //Print out received data
temp0 = prx_spitalk(0x00);
printf("Result: %02X\r",temp0); //Print out received data
temp0 = prx_spitalk(0x00);
printf("Result: %02X\r",temp0); //Print out received data
disable_prx();
enable_prx();
prx_spitalk(0xE2); //Flush RX FIFO
disable_prx();
enable_prx();
prx_spitalk(0x07); //Read the status register
temp0 = prx_spitalk(0x00);
printf("Post-TX PRX Status Register: %02X\r",temp0); //Print out status register
disable_prx();
enable_prx();
prx_spitalk(0x27); //Clear the RX_DR bit in the status register
prx_spitalk(0x40);
disable_prx();
enable_prx();
prx_spitalk(0x07);
temp0 = prx_spitalk(0x00);
printf("Post-TX PRX Status Register [INT Cleared]: %02X\r",temp0); //Print out status register
disable_prx();
showregisters_ptx();
showregisters_prx();
while (1)
{
};
}
int ptx_spitalk(int sendbyte)
{
/*
Desc: This function enables talking to the PTX nRF24L01 chip.
Inputs: The "sendbyte" part of this function is the byte to be sent to the
chip. If this data transfer cycle is only used to retrieve the next byte,
EX: getting a register value, this variable should be a 0x00.
Notes: Application must assert the TX_CSN line before function can be called.
This is due to the nature of multi-byte sending and receiving of which this
function is unaware of. Before calling a series of "ptx_spitalk" functions
assert the PTX chip's CSN line to low by using the function "enable_ptx();".
After transfer is complete the CSN line must be asserted high again by using
the function "disable_ptx();".
*/
int temp0,temp1, i, receivebyte;
receivebyte = 0;
for(i = 7; i >= 0; i--)
{
temp0 = sendbyte;
temp0 = temp0 >>i; //Shift the temp0 variable by "i" bits
temp0 = temp0 & 0x01; //And the shifted variable with 0x01 (0b00000001)
MOSI = temp0; //Set the Master Out (Slave In) pin with the bit value of temp0
SCK = 1; //Master Out is now asserted, clock in the data by pulsing SCK high
temp1 = MISO; //Grab the bit that the slave device (PTX) has sent and save in temp1
SCK = 0; //Transfer is complete, drop the SCK pulse
/*
Now we need to add temp1 to the receivebyte variable. This line gets a compile
warning as it could possibly overflow an int. The math we will be doing using the
pow(x,y); function will NOT overflow an int as the highest we will ever return from
this function is a 255, or 0xFF. To disable the warning for this specific line we
will use the #pragma warn- call and then re-enable with #pragma warn+ afterwards.
*/
#pragma warn-
receivebyte = receivebyte + pow((temp1*2),i); //Math needed to add up the result
#pragma warn+
}
return receivebyte;
}
int prx_spitalk(int sendbyte)
{
/*
Desc: This function enables talking to the PRX nRF24L01 chip.
Inputs: The "sendbyte" part of this function is the byte to be sent to the
chip. If this data transfer cycle is only used to retrieve the next byte,
EX: getting a register value, this variable should be a 0x00.
Notes: Application must assert the RX_CSN line before function can be called.
This is due to the nature of multi-byte sending and receiving of which this
function is unaware of. Before calling a series of "prx_spitalk" functions
assert the PRX chip's CSN line to low by using the function "enable_prx();".
After transfer is complete the CSN line must be asserted high again by using
the function "disable_prx();".
*/
int temp0,temp1, i, receivebyte;
receivebyte = 0;
for(i = 7; i >= 0; i--)
{
temp0 = sendbyte;
temp0 = temp0 >>i; //Shift the temp0 variable by "i" bits
temp0 = temp0 & 0x01; //And the shifted variable with 0x01 (0b00000001)
MOSI = temp0; //Set the Master Out (Slave In) pin with the bit value of temp0
SCK = 1; //Master Out is now asserted, clock in the data by pulsing SCK high
temp1 = MISO; //Grab the bit that the slave device (PRX) has sent and save in temp1
SCK = 0; //Transfer is complete, drop the SCK pulse
/*
Now we need to add temp1 to the receivebyte variable. This line gets a compile
warning as it could possibly overflow an int. The math we will be doing using the
pow(x,y); function will NOT overflow an int as the highest we will ever return from
this function is a 255, or 0xFF. To disable the warning for this specific line we
will use the #pragma warn- call and then re-enable with #pragma warn+ afterwards.
*/
#pragma warn-
receivebyte = receivebyte + pow((temp1*2),i); //Math needed to add up the result
#pragma warn+
}
return receivebyte;
}
void enable_ptx(void)
{
TX_CSN = 0; //Lower the CSN line for the PTX -- Begin data transfer
}
void disable_ptx(void)
{
TX_CSN = 1; //Raise the CSN line for the PTX -- Data transfer complete
}
void enable_prx(void)
{
RX_CSN = 0; //Lower the CSN line for the PRX -- Begin data transfer
}
void disable_prx(void)
{
RX_CSN = 1; //Raise the CSN line for the PRX -- Data transfer complete
}
void config_ptx(void)
{
//config PTX
enable_ptx();
ptx_spitalk(0x20);
ptx_spitalk(0x5C);
disable_ptx();
enable_ptx();
ptx_spitalk(0x24);
ptx_spitalk(0x00);
disable_ptx();
enable_ptx();
ptx_spitalk(0x23);
ptx_spitalk(0x03);
disable_ptx();
enable_ptx();
ptx_spitalk(0x26);
ptx_spitalk(0x07);
disable_ptx();
enable_ptx();
ptx_spitalk(0x25);
ptx_spitalk(0x02);
disable_ptx();
enable_ptx();
ptx_spitalk(0x30);
ptx_spitalk(0xE7);
ptx_spitalk(0xE7);
ptx_spitalk(0xE7);
ptx_spitalk(0xE7);
ptx_spitalk(0xE7);
disable_ptx();
enable_ptx();
ptx_spitalk(0x21);
ptx_spitalk(0x00);
disable_ptx();
enable_ptx();
ptx_spitalk(0x27);
ptx_spitalk(0x7E);
disable_ptx();
enable_ptx();
ptx_spitalk(0x20);
ptx_spitalk(0x5E);
disable_ptx();
}
void config_prx(void)
{
//config PRX
enable_prx();
prx_spitalk(0x20);
prx_spitalk(0x3D);
disable_prx();
enable_prx();
prx_spitalk(0x21);
prx_spitalk(0x00);
disable_prx();
enable_prx();
prx_spitalk(0x23);
prx_spitalk(0x03);
disable_prx();
enable_prx();
prx_spitalk(0x26);
prx_spitalk(0x07);
disable_prx();
enable_prx();
prx_spitalk(0x31);
prx_spitalk(0x04);
disable_prx();
enable_prx();
prx_spitalk(0x25);
prx_spitalk(0x02);
disable_prx();
enable_prx();
prx_spitalk(0x30);
prx_spitalk(0xE7);
prx_spitalk(0xE7);
prx_spitalk(0xE7);
prx_spitalk(0xE7);
prx_spitalk(0xE7);
disable_prx();
enable_prx();
prx_spitalk(0x20);
prx_spitalk(0x3F);
disable_prx();
enable_prx();
prx_spitalk(0xE2);
disable_prx();
RX_CE = 1; //activate receiver
}
void showregisters_ptx(void)
{
int temp[5], i;
//This is a debugging function. It will output the current status of all registers.
printf("Status of PTX registers:\r");
for(i=0; i<0x0A; i++)
{
showregisters_ptx_macro(i);
}
enable_ptx();
ptx_spitalk(0x0A);
temp[0] = ptx_spitalk(0x00);
temp[1] = ptx_spitalk(0x00);
temp[2] = ptx_spitalk(0x00);
temp[3] = ptx_spitalk(0x00);
temp[4] = ptx_spitalk(0x00);
printf("Register $0A's Value: %02X%02X%02X%02X%02X\r",temp[4],temp[3],temp[2],temp[1],temp[0]);
disable_ptx();
enable_ptx();
ptx_spitalk(0x0B);
temp[0] = ptx_spitalk(0x00);
temp[1] = ptx_spitalk(0x00);
temp[2] = ptx_spitalk(0x00);
temp[3] = ptx_spitalk(0x00);
temp[4] = ptx_spitalk(0x00);
printf("Register $0B's Value: %02X%02X%02X%02X%02X\r",temp[4],temp[3],temp[2],temp[1],temp[0]);
disable_ptx();
for(i=0x0C; i<0x10; i++)
{
showregisters_ptx_macro(i);
}
enable_ptx();
ptx_spitalk(0x10);
temp[0] = ptx_spitalk(0x00);
temp[1] = ptx_spitalk(0x00);
temp[2] = ptx_spitalk(0x00);
temp[3] = ptx_spitalk(0x00);
temp[4] = ptx_spitalk(0x00);
printf("Register $10's Value: %02X%02X%02X%02X%02X\r",temp[4],temp[3],temp[2],temp[1],temp[0]);
disable_ptx();
for(i=0x11; i<0x18; i++)
{
showregisters_ptx_macro(i);
}
showregisters_ptx_macro(0x1C);
showregisters_ptx_macro(0x1D);
printf("Status of PTX registers complete...\r\r");
}
void showregisters_ptx_macro(int usereg)
{
int temp0;
enable_ptx();
ptx_spitalk(usereg);
temp0 = ptx_spitalk(0x00);
printf("Register $%02X's Value: %02X\r",usereg,temp0);
disable_ptx();
}
void showregisters_prx(void)
{
int temp[5], i;
//This is a debugging function. It will output the current status of all registers.
printf("Status of PRX registers:\r");
for(i=0; i<0x0A; i++)
{
showregisters_prx_macro(i);
}
enable_prx();
prx_spitalk(0x0A);
temp[0] = prx_spitalk(0x00);
temp[1] = prx_spitalk(0x00);
temp[2] = prx_spitalk(0x00);
temp[3] = prx_spitalk(0x00);
temp[4] = prx_spitalk(0x00);
printf("Register $0A's Value: %02X%02X%02X%02X%02X\r",temp[4],temp[3],temp[2],temp[1],temp[0]);
disable_prx();
enable_prx();
prx_spitalk(0x0B);
temp[0] = prx_spitalk(0x00);
temp[1] = prx_spitalk(0x00);
temp[2] = prx_spitalk(0x00);
temp[3] = prx_spitalk(0x00);
temp[4] = prx_spitalk(0x00);
printf("Register $0B's Value: %02X%02X%02X%02X%02X\r",temp[4],temp[3],temp[2],temp[1],temp[0]);
disable_prx();
for(i=0x0C; i<0x10; i++)
{
showregisters_prx_macro(i);
}
enable_prx();
prx_spitalk(0x10);
temp[0] = prx_spitalk(0x00);
temp[1] = prx_spitalk(0x00);
temp[2] = prx_spitalk(0x00);
temp[3] = prx_spitalk(0x00);
temp[4] = prx_spitalk(0x00);
printf("Register $10's Value: %02X%02X%02X%02X%02X\r",temp[4],temp[3],temp[2],temp[1],temp[0]);
disable_prx();
for(i=0x11; i<0x18; i++)
{
showregisters_prx_macro(i);
}
showregisters_prx_macro(0x1C);
showregisters_prx_macro(0x1D);
printf("Status of PRX registers complete...\r\r");
}
void showregisters_prx_macro(int usereg)
{
int temp[5];
enable_prx();
prx_spitalk(usereg);
temp[0] = prx_spitalk(0x00);
printf("Register $%02X's Value: %02X\r",usereg,temp[0]);
disable_prx();}
// External Interrupt 0 service routine
interrupt [EXT_INT0] void ext_int0_isr(void)
{
// Place your code here
printf("Ext Int0 Executed");
}
// External Interrupt 1 service routine
interrupt [EXT_INT1] void ext_int1_isr(void)
{
// Place your code here
printf("Ext Int1 Executed");
}
Here’s the terminal output
Text display test: [OK]
Text display test: [OK]
Text display test: [OK]
Text display test: [OK]
Text display test: [OK]
Text display test: [OK]
Text display test: [OK]
Text display test: [OK]
Text display test: [OK]
Text display test: [OK]
Text display test: [OK]
Text display test: [OK]
Text display test: [OK]
Text display test: [OK]
Text display test: [OK]
Setting up PRX/PTX...
Done setting up PRX/PTX...
Status of PTX registers:
Register $00's Value: 5E
Register $01's Value: 00
Register $02's Value: 03
Register $03's Value: 03
Register $04's Value: 00
Register $05's Value: 02
Register $06's Value: 07
Register $07's Value: 0E
Register $08's Value: 00
Register $09's Value: 00
Register $0A's Value: E7E7E7E7E7
Register $0B's Value: C2C2C2C2C2
Register $0C's Value: C3
Register $0D's Value: C4
Register $0E's Value: C5
Register $0F's Value: C6
Register $10's Value: E7E7E7E7E7
Register $11's Value: 00
Register $12's Value: 00
Register $13's Value: 00
Register $14's Value: 00
Register $15's Value: 00
Register $16's Value: 00
Register $17's Value: 11
Register $1C's Value: 00
Register $1D's Value: 00
Status of PTX registers complete...
Status of PRX registers:
Register $00's Value: 3F
Register $01's Value: 00
Register $02's Value: 03
Register $03's Value: 03
Register $04's Value: 03
Register $05's Value: 02
Register $06's Value: 07
Register $07's Value: 0E
Register $08's Value: 00
Register $09's Value: 00
Register $0A's Value: E7E7E7E7E7
Register $0B's Value: C2C2C2C2C2
Register $0C's Value: C3
Register $0D's Value: C4
Register $0E's Value: C5
Register $0F's Value: C6
Register $10's Value: E7E7E7E7E7
Register $11's Value: 04
Register $12's Value: 00
Register $13's Value: 00
Register $14's Value: 00
Register $15's Value: 00
Register $16's Value: 00
Register $17's Value: 11
Register $1C's Value: 00
Register $1D's Value: 00
Status of PRX registers complete...
Pre-TX PTX Status Register: 0F
Pre-TX PRX Status Register: 0E
Data Transmit about to occur!
Post-TX PTX Status Register: 2E
Post-TX PTX Status Register [INT Cleared]: 0E
Result: 00
Result: 00
Result: 00
Result: 00
Post-TX PRX Status Register: 0E
Post-TX PRX Status Register [INT Cleared]: 0E
Status of PTX registers:
Register $00's Value: 5E
Register $01's Value: 00
Register $02's Value: 03
Register $03's Value: 03
Register $04's Value: 00
Register $05's Value: 02
Register $06's Value: 07
Register $07's Value: 0E
Register $08's Value: 00
Register $09's Value: 00
Register $0A's Value: E7E7E7E7E7
Register $0B's Value: C2C2C2C2C2
Register $0C's Value: C3
Register $0D's Value: C4
Register $0E's Value: C5
Register $0F's Value: C6
Register $10's Value: E7E7E7E7E7
Register $11's Value: 00
Register $12's Value: 00
Register $13's Value: 00
Register $14's Value: 00
Register $15's Value: 00
Register $16's Value: 00
Register $17's Value: 11
Register $1C's Value: 00
Register $1D's Value: 00
Status of PTX registers complete...
Status of PRX registers:
Register $00's Value: 3F
Register $01's Value: 00
Register $02's Value: 03
Register $03's Value: 03
Register $04's Value: 03
Register $05's Value: 02
Register $06's Value: 07
Register $07's Value: 0E
Register $08's Value: 00
Register $09's Value: 00
Register $0A's Value: E7E7E7E7E7
Register $0B's Value: C2C2C2C2C2
Register $0C's Value: C3
Register $0D's Value: C4
Register $0E's Value: C5
Register $0F's Value: C6
Register $10's Value: E7E7E7E7E7
Register $11's Value: 04
Register $12's Value: 00
Register $13's Value: 00
Register $14's Value: 00
Register $15's Value: 00
Register $16's Value: 00
Register $17's Value: 11
Register $1C's Value: 00
Register $1D's Value: 00
Status of PRX registers complete...
So…anyone here able to figure out what’s not setup right? I’ve tried mostly everything I know, yet I can’t get the PRX chip to receive a transfer.