how to nRF24L01 using kl25z?

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

how to nRF24L01 using kl25z?

3,332 Views
gabrieltakaokan
Contributor I

Hey guys I'm trying to implement a simple transmitter using the KL25Z and the Nordic nRF24L01.

The KL25Z is the transmitter and a Arduino is a receiver (which I've successfuly got it working arduino x arduino) :

Arduino x KL25Z is not working well though. I'm using this tutorial and configuring the sender like this:

#define PAYLOAD_SIZE 8  /* number of payload bytes, 0 to 32 bytes */

#define CHANNEL_NO   76  /* communication channel */

static const uint8_t TADDR[5] = {0x0F, 0x0F, 0x0F, 0xD2, 0xD2}; /* device address */

static const uint8_t RADDR[5] = {0x0f, 0x0f, 0x0f, 0x0f, 0xd1}; /* device address */

static uint8_t payload[PAYLOAD_SIZE]; /* buffer for payload */

RF_Init(); /* set CE and CSN to initialization value */

  RF_WriteRegister(RF24_RF_SETUP, RF24_RF_SETUP_RF_PWR_0|RF24_RF_SETUP_RF_DR_1000);

  RF_WriteRegister(RF24_RX_PW_P0, PAYLOAD_SIZE); /* number of payload bytes we want to send and receive */

  RF_WriteRegister(RF24_RX_PW_P1, PAYLOAD_SIZE); /* number of payload bytes we want to send and receive */

  RF_WriteRegister(RF24_RF_CH, CHANNEL_NO); /* set channel */

  /* Set RADDR and TADDR as the transmit address since we also enable auto acknowledgment */

  RF_WriteRegisterData(RF24_RX_ADDR_P0, (uint8_t*)TADDR, sizeof(TADDR));

  RF_WriteRegisterData(RF24_TX_ADDR, (uint8_t*)TADDR, sizeof(TADDR));

  RF_WriteRegisterData(RF24_RX_ADDR_P1, (uint8_t*)RADDR, sizeof(RADDR));

  /* Enable RX_ADDR_P0 address matching */

  RF_WriteRegister(RF24_EN_RXADDR, RF24_EN_RXADDR_ERX_P0 | RF24_EN_RXADDR_ERX_P1); /* hoping that P0 and P1 are enabled by now */

/* clear interrupt flags */

  RF_ResetStatusIRQ(RF24_STATUS_RX_DR|RF24_STATUS_TX_DS|RF24_STATUS_MAX_RT);

RF_WriteRegister(RF24_EN_AA, RF24_EN_AA_ENAA_P0); /* enable auto acknowledge. RX_ADDR_P0 needs to be equal to TX_ADDR! */

  RF_WriteRegister(RF24_SETUP_RETR, RF24_SETUP_RETR_ARD_750|RF24_SETUP_RETR_ARC_15); /* Important: need 750 us delay between every retry */

  TX_POWERUP();  /* Power up in transmitting mode */

  CE_ClrVal();   /* Will pulse this later to send data */

Now for the problems.

1) Is this the right way to configure channels?

  RF_WriteRegister(RF24_RF_CH, CHANNEL_NO); /* set channel */

2) How should I enable P0 AND P1 (if I need to receive)?

  RF_WriteRegister(RF24_EN_RXADDR, RF24_EN_RXADDR_ERX_P0 | RF24_EN_RXADDR_ERX_P1); /* hoping that P0 and P1 are enabled by now */

3) Is there any bad choice of pins? I tried the same as the tutorial. (but when trying to implement in MBED they said to avoid PTD1 - Blue LED)

4) How do I know if the message was successfuly sent? In arduino there's a function that returns true if success

0 Kudos
11 Replies

1,783 Views
BlackNight
NXP Employee
NXP Employee

FYI, good catch by Marc:

using RF24_CRCO means two byte CRC (as stated in the data sheet).

So my original comment was wrong (fixed below):

  RF_WriteRegister(RF24_CONFIG, RF24_EN_CRC|RF24_CRCO|RF24_PWR_UP|RF24_PRIM_TX); /* enable 2 byte CRC, power up and set as PTX */ /* Power up in transmitting mode */ 

Regards,

Erich

0 Kudos

1,783 Views
mjbcswitzerland
Specialist V

Hi

1) RF_WriteRegister(RF24_RF_CH, CHANNEL_NO); configures the RF channel (for both local rx and tx) which must be the same at receiver and transmitter.

2) RF_WriteRegister(RF24_EN_RXADDR, RF24_EN_RXADDR_ERX_P0 | RF24_EN_RXADDR_ERX_P1); enabled endpipes 0 and 1 for reception.

3) You can use the blue LED control line if you want - it will simply cause the blue LED to be controlled as well.

4) When a message is sent there is an ACK received (if the receiver is on the same channel, has the same rx address as the tx address and is sending acks on reception) which results in STATUS_TX_DS being set in the status register, plus an interrupt, if enabled. If there is no acknowledgement after the programmed number of repetitions the bit STATUS_MAX_RT is set in the status register and also, if enable, an  interrupt occurs.

You can either write the transmitter as blocking (waits until the result is known before returning) or else interrupt driven. It sounds like mbed is blocking if it returns a result (generally a simple and inefficient solution since it may block for about 10ms if there is no receiver present). It is recommended to use the interrupt method as in the tutorial unless you are running under a pre-emptive operating system.

Regards

Mark

0 Kudos

1,783 Views
gabrieltakaokan
Contributor I

Thanks for the quick answer!

Okay, I've got some more questions.

5) What frequency should I set SCLK? I'm setting it to 524.288kHz but I'm not sure why.

In the arduino I dont get to set that, everything happens under SPI class.

6) As for pipe mapping my arduino is set to receive from 0x0F0F0F0FD2.

Is it alright to set the freedom address to

static const uint8_t TADDR[5] = {0x0F, 0x0F, 0x0F, 0xD2, 0xD2}; /* device address */

?

Regards,

Gabriel

0 Kudos

1,783 Views
mjbcswitzerland
Specialist V

Hi

5) SCLK can be set to any frequency up to 10MHz (this is the limit of the nRF24L01+).
If the arduino SPI class doesn't allow the user to define this speed it is not a good solution; this is an important parameter that the user should be able to define. The SPI mode is 0,0 (SCLK idle state is '0' and data is clocked on rising clock edges), which also has to be set correctly.

6) The freedom board's Rx and Tx addresses should be set to the same as the arduino's using that pattern.

Regards

Mark

0 Kudos

1,783 Views
gabrieltakaokan
Contributor I

So I've modified the code so it only transmits as following:

#define PAYLOAD_SIZE 16  /* number of payload bytes, 0 to 32 bytes */

#define CHANNEL_NO   44  /* communication channel *

//static const uint8_t TADDR[5] = {0x0F, 0x0F, 0x0F, 0x0F, 0xD2}; /* device address */

static const uint8_t TADDR[5] = {0x0F, 0x0F, 0x0F, 0x0F, 0xE1}; /* device address */

static uint8_t payload[PAYLOAD_SIZE]; /* buffer for payload */

void APP_Run(void) {

  int i, cntr;

  uint8_t status;

  WAIT1_Waitms(100); /* give device time to power up */

  RF_Init(); /* set CE and CSN to initialization value */

 

  RF_WriteRegister(RF24_RF_SETUP, RF24_RF_SETUP_RF_PWR_0|RF24_RF_SETUP_RF_DR_1000);

  RF_WriteRegister(RF24_RX_PW_P0, PAYLOAD_SIZE); /* number of payload bytes we want to send and receive */

  RF_WriteRegister(RF24_RF_CH, CHANNEL_NO); /* set channel */

 

  /* Set RADDR and TADDR as the transmit address since we also enable auto acknowledgment */

  RF_WriteRegisterData(RF24_RX_ADDR_P0, (uint8_t*)TADDR, sizeof(TADDR));

  RF_WriteRegisterData(RF24_TX_ADDR, (uint8_t*)TADDR, sizeof(TADDR));

  /* Enable RX_ADDR_P0 address matching */

  RF_WriteRegister(RF24_EN_RXADDR, RF24_EN_RXADDR_ERX_P0); /* hoping that P0 is enabled */

  /* clear interrupt flags */

  RF_ResetStatusIRQ(RF24_STATUS_RX_DR|RF24_STATUS_TX_DS|RF24_STATUS_MAX_RT);

  RF_WriteRegister(RF24_EN_AA, RF24_EN_AA_ENAA_P0); /* enable auto acknowledge. RX_ADDR_P0 needs to be equal to TX_ADDR! */

  RF_WriteRegister(RF24_SETUP_RETR, RF24_SETUP_RETR_ARD_1500|RF24_SETUP_RETR_ARC_15); /* Important: need 750 us delay between every retry */

  RF_WriteRegister(RF24_CONFIG, RF24_EN_CRC|RF24_CRCO|RF24_PWR_UP|RF24_PRIM_TX); /* enable 1 byte CRC, power up and set as PTX */ /* Power up in transmitting mode */

  CE_ClrVal();   /* Will pulse this later to send data */

  cntr = 0;

  for(;;) { // while(true)

       cntr++;

       if (cntr == 3000) { /* send data every 3000 ms */

            cntr = 0;

            RED_LED_SetVal();

            for(i = 0; i < PAYLOAD_SIZE; i++) { // populate payload

            payload[i] = i + 1;

       }

  RF_TxPayload(payload, sizeof(payload)); /* send data */

  RED_LED_ClrVal();

  }

  if (isrFlag) { /* check if we have received an interrupt */

  //APP_BlinkNTimesEachTMS(1, 400, 0);

  isrFlag = FALSE; /* reset interrupt flag */

  status = RF_GetStatus();

    if (status&RF24_STATUS_RX_DR) { /* data received interrupt */

    RF_ResetStatusIRQ(RF24_STATUS_RX_DR); /* clear bit */

    }

  if (status&RF24_STATUS_TX_DS) { /* data sent interrupt */

  cntr = 0; /* reset timeout counter */

  RED_LED_ClrVal(); /* indicate data has been sent */

  RF_ResetStatusIRQ(RF24_STATUS_TX_DS); /* clear bit */

  }

  if (status&RF24_STATUS_MAX_RT) { /* retry timeout interrupt */

  RF_ResetStatusIRQ(RF24_STATUS_MAX_RT); /* clear bit */

  }

  }

  WAIT1_Waitms(1);

  }

}

It is falling into this if

  if (status&RF24_STATUS_MAX_RT) { /* retry timeout interrupt */

What should I do? I've tried to switch addresses, channels and everything else

Comparing to arduino output:

Untitled (1).png

I dont really know what I'm doing wrong.

0 Kudos

1,783 Views
mjbcswitzerland
Specialist V

Hi

Check how RF24_CRCO is defined.

If it is not 0 it is in fact enabling 2 CRC bytres and so would mismatch with what the arduino setting states.

If this is the case the comment in the tutorial is incorrect (I always suspected the comment but don't use the tutorial code so never looked in detail).

Also try sending to endpipe 0 rather than endpipe 1 - it may be that only endpipe 0 responds with ACK (the RF chip is quite useful but doesn't always behave as expected and as detailed in the data sheet).

Also be very careful when controlling the TX_ENABLE output. Never keep it at '1' for more that 4ms since this could destroy something (or make the chip crazy forever more) [see warning in the data sheet in section 6.1.5]. In fact I only ever use the Enhanced ShockBurts(TM) mode because it has many advantages, including that it can't destroy itself.

Regards

Mark

0 Kudos

1,783 Views
gabrieltakaokan
Contributor I

Okay so by the nRF24L01.h header file I've get the definition of RF24_CRCO:

#define RF24_CRCO        (1<<2)  /* CRC encoding scheme, 0: 1 byte, 1: 2 bytes */

And is used here:

RF_WriteRegister(RF24_CONFIG, RF24_EN_CRC|RF24_CRCO|RF24_PWR_UP|RF24_PRIM_TX); /* enable ? byte CRC, power up and set as PTX */ /* Power up in transmitting mode */

Versus arduino modular code (configuring crc length)

typedef enum { RF24_CRC_DISABLED = 0, RF24_CRC_8, RF24_CRC_16 } rf24_crclength_e;

void RF24::setCRCLength(rf24_crclength_e length)

{

  uint8_t config = read_register(CONFIG) & ~( _BV(CRCO) | _BV(EN_CRC)) ;

 

  // switch uses RAM (evil!)

  if ( length == RF24_CRC_DISABLED )

  {

    // Do nothing, we turned it off above.

  }

  else if ( length == RF24_CRC_8 )

  {

    config |= _BV(EN_CRC);

  }

  else

  {

    config |= _BV(EN_CRC);

    config |= _BV( CRCO );

  }

  write_register( CONFIG, config ) ;

}

(configuring PRIMARY_TX)

write_register(CONFIG, ( read_register(CONFIG) | _BV(PWR_UP) ) & ~_BV(PRIM_RX) );

Is there anything that I should modify? Doesnt look like.

How do I send with endpipe 0?

I'm not sure when TX_ENABLE output is used though. How to enable Enhanced ShockBursts(TM)?

Thanks,

Gabriel

0 Kudos

1,783 Views
mjbcswitzerland
Specialist V

Hi

I don't see where the arduino code is actually setting the CRC but from the output it is CONFIG = 0x0b. This is EN_CRC only, corresponding to teh arduino enum of RF24_CRC_8.

As see from the define RF_CRCO being 0x04 it means that the tutorial's comment "? byte CRC"means that the actual number fo bytes was probably unknown, but is clearly 2.

This means that this is not compatible with arduino's single byte setting.

You therefore need to remove the RF_CRC0 bit.

The transmitter doesn't send over an endpipe - only the receiver receives on an endpipe. Each receiver's endpipe has a different address, therefore by sending to the correct address the transmitter is automatically sending to a specific receiver's endpipe.

In default mode TX_ENABLE is pulsed to cause the transmitter to send (> 10us) or is set to '1' continuously for a receiver to listen. In Enhanced ShockBurst(TM) mode this is "can" be set to '1' all the time for a receiver to listen and for a transmitter to send automatically when there is something in its output FIFO.

The Enhanced ShockBurst(TM) mode is available in nRF24L01+ and is enabled by default in the EN_AA register (0x01). If you have nRF24L01+ and nRF24L04 (without the +) you will in fact have to disabled it and also ensure that 2Mbps is not used. It looks like the tutorial is using this due to the fact that there are a number of automatic retransmissions programmed [see also RF_WriteRegister(RF24_EN_AA, RF24_EN_AA_ENAA_P0); /* enable auto acknowledge. RX_ADDR_P0 needs to be equal to TX_ADDR! */] - however it looks like arduino has it disabled due to EN_AA being 0x00. Therefore it looks like arduino is not performing automatic acks so this may also be a further incompatibility.

My feelings are therefore:

- CRC is mismatching so no all data will be ignored. If they match you may then get receptions working

- Enhanced ShockBurst(TM) is enabled at one side but not the other. This probably won't stop data from being received at the destination but the transmitter will not receive an ACK back so will declare an error (after repeating a few times).

Regards

Mark

0 Kudos

1,783 Views
gabrieltakaokan
Contributor I

Okay so now I've got CONFIG 0x0f in the arduino side.

By doing this

radio.openReadingPipe(1,0xF0F0F0F0E1LL);

I've set P1 to 0xF0F0F0F0E1LL right? Since the only address on the KL25Z is

static const uint8_t TADDR[5] = {0x0F, 0x0F, 0x0F, 0x0F, 0xE1};

I can therefore assume everything's okay in the pipe mapping matter.

Configuring CRC to 16 bits AA's set to 0x3F.

Untitled.png

So what's not working now?

I debugged the isrFlag, that only triggers at

if (status&RF24_STATUS_MAX_RT) { /* retry timeout interrupt */

Any ideas?

0 Kudos

1,783 Views
mjbcswitzerland
Specialist V

Hi

Try using endpipe 0. As I mentioned earlier I don't know whether all endpoints ACK correctly. Endpoint 0 certainly does though.

Also see whether the arduino receiver is actually receiving anything. If not the problem is the direction -> arduino. If it does, the problem is in the ACK direction (which doesn't mean that the receiver doesn't receive the data correctly).

Regards

Mark

0 Kudos

1,783 Views
gabrieltakaokan
Contributor I

I've tried using endpipe 0 as in changing rx pipe in arduino side.

radio.openReadingPipe(0,pipes[0]);

Didn't work as well.

0 Kudos