Tutorial: Nordic Semiconductor nRF24L01+ with the Freescale FRDM-K64F Board

For some time I’m using the Nordic Semiconductor nRF24L01+ transceiver successfully in many projects (see “Tutorial: Ultra Low Cost 2.4 GHz Wireless Transceiver with the FRDM Board“). Since that tutorial things evolved a lot with the introduced RNet Stack. To honor the popularity of the Nordic Semiconductor nRF24L01+, Freescale has put a socket on the FRDM-K64F board. So time to make a new step-by-step tutorial how to use the nRF24L01+ with the FRDM-K64F.

Two FRDM-K64F Boards with nRF24L01+ Transceiver

Two FRDM-K64F Boards with nRF24L01+ Transceiver

I apologize that it took so long until I have found the week-end and night hours to write this up: I had the transceivers and boards quickly working after I have received the boards back in April this year. But writing a tutorial takes much more time than what I needed to write the application itself. Probably I’m doing that kind of software+hardware too many times, so it does not sound like a big deal for me. But I have received several requests to help them combining the Freescale FRDM-K64F board with the Nordic Semiconductor nRF24L01+ transceiver, so here we go…..

Outline

In this tutorial, I show the steps how to use the nRF24L01+ transceiver and RNet stack with the FRDM-K64F board.To keep things simple, the board will send periodically a PING message to another board. I’m using in this tutorial Eclipse Kepler with Processor Expert, but any other Eclipse based tool with Processor Expert (e.g. Kinetis Design Studio, IAR or Keil) can be used. Make sure you have loaded my latest Processor Expert components from GitHub, see “Processor Expert Component *.PEupd Files on GitHub“. In this tutorial I assume you have basic Eclipse and Processor Expert knowledge.

Hardware

You need a board (FRDM-K64F), a transceiver (nRF24L01+, you find many sources on the internet, I have mine from here: http://yourduino.com/sunshop2/index.php?l=product_detail&p=188), headers and basic soldering skills ;-). And you need this twice to communicate between two boards.

FRDM-K64F with nRF24L01+ Transceiver and Headers

FRDM-K64F with nRF24L01+ Transceiver and Headers

Solder the header to the board:

Headers soldered

Headers soldered

Then put the module on the header:

❗ Check and verify the pin out of the module with the pins on the FRDM-K64F board. The pin mapping for the RF module are on the back of the FRDM-K64F board.

nRF24L01+ Module on Header

nRF24L01+ Module on Header

Creating Project

In Eclipse, create a new project for the FRDM-K64F for the MK64FN1M0VLL12 device on the board. Make sure you have the project with Processor Expert enabled. With this, I get a basic (empty) project for the FRDM-K64F:

Project for FRDM-K64F

Project for FRDM-K64F

FreeRTOS Component

I’m going to use the RNet stack for my communication, and this stack uses the FreeRTOS queues for message buffering. While it would be possible to use any kind of buffers (ring buffer, etc), I keep using FreeRTOS in this tutorial, as it simplifies things a lot, and I can use it later for a more complex application.

So I’m adding the FreeRTOS Processor Expert component to the project. It will automatically add the Utility component too:

FreeRTOS added

FreeRTOS added

The RTOS gets configured to use the Cortex-M4F as this is the processor on the FRDM-K64F:

Floating Point Settings in FreeRTOS for K64F

Floating Point Settings in FreeRTOS for K64F

As we will need some Heap RAM for the transceiver buffers and stack, I increase the FreeRTOS heap size from the default 2K to something around 20k (I have plenty of RAM on the K64F):

FreeRTOS Heap Size

FreeRTOS Heap Size

Compiler Settings

In the project settings, I need to verify that the settings are matching a Cortex-M4 with hardware floating point unit (fpv4-sp-d16):

Floating Point Settings in GNU ARM

Floating Point Settings in GNU ARM

CPU Clocks

Next I’m configuring the CPU clocks. I just configure a rather high clock, so I will have a high clock for the SPI used by the nRF24L01+ transceiver. To reach an even higher CPU clock, see “FRDM-K64F at Maximum Speed of 120 MHz“. In this tutorial I’m using the 32 kHz RTC clock as reference. For this I enable the RTC clock in FEI mode:

K64F Clock Settings with RTC

K64F Clock Settings with RTC

The FLL clock gets configured to 96 MHz (or close to this):

FLL set to 96 MHz

FLL set to 96 MHz

Based on that 96 MHz clock, I can configure the clocks for the core and peripherals:

System Clocks Configured

System Clocks Configured

SPI Component

The nRF24L01+ uses an SPI interface to the microcontroller. I can use it two ways:

  1. Hardware SPI: in this case the microcontroller hardware SPI peripheral is used. This is the preferred way, as the hardware does all the bit shifting and clocking. But in that case the transceiver module needs to be connected to hardware SPI pins on the microcontroller.
  2. Software SPI: here normal general purpose (GPIO) pins are used. This is called ‘bit banging’, and the software does all the shifting and clocking. This takes a lot of CPU cycles, but the last resort e.g. if no hardware SPI is available.

On the FRDM-K64F board, luckily the pins are connected to the hardware SPI, so I add the SynchroMaster (Hardware SPI) component to the project:

SynchroMaster SPI Component Added

SynchroMaster SPI Component Added

The component shows errors, as it is not configured yet. According to the FRDM-K64F schematics, I need to assign the following pins for the SPI1 channel:

  • Interrupts enabled
  • MISO: PTD7
  • MOSI: PTD6
  • Clock: PTD5
  • Slave Select pin disabled (the nRF24L01+ driver will do this)
  • Clock Speed: the nRF24L01+ allows a maximum clock speed of 8 MHz.
  • The Clock edge needs to be set to *falling edge*. This will set the SPI clock and data to ‘data is valid on clock leading/rising edge (CPHA=0).
  • The Shift clock idle polarity is set to *Low* (CPOL=0)
  • MSB (Most Significant Bit) first (MSB needs to be shifted first)
Hardware SPI Settings for nRF24L01+

Hardware SPI Settings for nRF24L01+

Software SPI

You *could* use the Software SPI too (you will need to select it in the RNet component, which comes next). In case you have no hardware SPI, then add the GenericSWSPI component to your project:

GenericSWSPI Component

GenericSWSPI Component

You need to configure the clock, input (MISO) and output (MOSI) pins to the pins on your board. The picture below shows the component settings:

  • Clock edge: Falling edge
  • Clock idle polarity: low
  • Output pin idle polarity: high
  • MSB first set to yes
Software SPI Settings for nRF24L01+

Software SPI Settings for nRF24L01+

RNet Component

Next I’m adding the RNet Wireless stack component:

RNet Component Added

RNet Component Added

nRF24L01+ Transceiver Component

I configure the RNet component to use the nRF24L01+ transceiver and add a new component for it in the drop down box of the component:

Configuring RNet Component

Configuring RNet Component

The RNet has other settings which we keep by default. Be free to change the settings once you have working version. You can configure the radio channel or the data rate. Both can be changed at runtime with methods provided by the component, so you can implement easily a channel hopping. The node network addresses are 8bit by default, so you can have up to 256 devices on a channel which should be enough for most cases. The address 0xFF (or 0xFFFF for 16bit addresses) are broadcast addresses.

The queues are used to buffer incoming or outgoing messages. For this FreeRTOS queues are used: Using more queues will consume more memory. Each element in the queue will hold a full message, which is in our case 32 bytes plus one overhead byte (so 33 bytes). The blocking time specifies how long the task shall wait if the queue is full.

Finally, a retry count can be specified. If greater than zero, it will retry to send the message if no acknowlege is received.

SPI Block Transfer

It asks me which SPI bus it shall us, and I can select the SPI component (SM1) I have configured in the previous step:

Using SPI for component

Using SPI for component

However, the RNet stack requests block send and receive methods on the SPI bus, and this is not provided by default. Looking at the description oft the method it tells me that I need to use buffers in the SPI component:

Block Send and Receive Needed

Block Send and Receive Needed

So I enable the buffers for SPI. The nRF24L01+ has a maximum payload of 32 bytes, so with the overhead I’m using 48 bytes each:

SPI Input and Output Buffers

SPI Input and Output Buffers

Now the SPI component is happy again.

CE and CSN Pins

But I need to assign the CE and CSN pins of the nRF24L01 component:

Pins for nRF24L01+

Pins for nRF24L01+

According to the schematics, CE is connected to PTC12 and CSN is connected to PTD4:

NOTE that depending on the revision of the board the CE pin is on PTB20 instead of PTC12! E.g. SCH-28163 REV E3 boards use PTB20 for CE pin!

CE Configured

CE Configured

CSN Configured

CSN Configured

Interrupt Pin

There is one pin missing: the interrupt pin of the nRF24L01+ module! So I enable the interrupt pin in the nRF24L01+ component:

Radio IRQ Pin Enabled

Radio IRQ Pin Enabled

The IRQ pin is routed to PTC18, triggering on falling edge:

Interrupt Pin of nRF24L01+ Configured

Interrupt Pin of nRF24L01+ Configured

This completes the hardware part for the nRF24L01+.

LEDs

Because I want to show the transceiver activity with LEDs’, I’m adding three LED components for the RGB LED of the board, configured to PTB22, PTE26 and PTB21:

LED Components Added

LED Components Added

Software Files

I’m going to add three source files to my project:

Software Stack Files

Software Stack Files

  1. RNet_App.c is my application file.
  2. RNet_App.h is my interface for the above file.
  3. RNet_AppConfig.h is my stack application configuration file.

I discuss below the most important parts of each file. For the complete source files, see the project link at the end of the article.

RNet_AppConfig.h

In this header file I can configure the stack settings (I keep the defaults). And I should declare here the content of RAPP_MSG_Type as this will be my messages types. So for this tutorial I’m defining a PING message with numerical ID 0x55:

/**
 * \file
 * \brief This is a configuration file for the RNet stack
 * \author (c) 2014 Erich Styger, https://mcuoneclipse.com/
 * \note MIT License (http://opensource.org/licenses/mit-license.html)
 *
 * Here the stack can be configured using macros.
 */

#ifndef __RNET_APP_CONFIG__
#define __RNET_APP_CONFIG__

/*! type ID's for application messages */
typedef enum {
  RAPP_MSG_TYPE_PING = 0x55,
} RAPP_MSG_Type;

#endif /* __RNET_APP_CONFIG__ */

RNet_App.h

RNet_App.h is the interface to RNet_App.c. All what I need for now is just to call the Init() method which will initialize everything for me:

/**
 * \file
 * \brief This is the interface to the application entry point.
 * \author (c) 2014 Erich Styger, https://mcuoneclipse.com/
 * \note MIT License (http://opensource.org/licenses/mit-license.html)
 */

#ifndef RNETAPP_H_
#define RNETAPP_H_

/*! \brief Driver initialization */
void RNETA_Init(void);

#endif /* RNETAPP_H_ */

RNet_App.c

The functionality of the application and stack is in RNet_App.c.

The Init() method initializes the RNet Stack with RSTACK_Init(), assigns a message handler (RAPP_SetMessageHandlerTable(), more about this later) and creates an RTOS task. The RTOS scheduler itself will be started in main().

void RNETA_Init(void) {
  RSTACK_Init(); /* initialize stack */
  if (RAPP_SetMessageHandlerTable(handlerTable)!=ERR_OK) { /* assign application message handler */
    for(;;); /* "ERR: failed setting message handler!" */
  }
  if (FRTOS1_xTaskCreate(
        RNetTask,  /* pointer to the task */
        "RNet", /* task name for kernel awareness debugging */
        configMINIMAL_STACK_SIZE, /* task stack size */
        (void*)NULL, /* optional task startup argument */
        tskIDLE_PRIORITY,  /* initial priority */
        (xTaskHandle*)NULL /* optional task handle to create */
      ) != pdPASS) {
    /*lint -e527 */
    for(;;){}; /* error! probably out of memory */
    /*lint +e527 */
  }
}

Radio Application Task

In this tutorial, the application runs in a single task: RNetTask(). I suggest to use one task just to deal with the radio transceiver, and add extra tasks for anything your application is doing otherwise. And make sure that the task is processing the state machine frequently enough. How much is ‘frequently engough’ depens on the amount of messages and buffer (queue) sizes. I recommend something of at least 20 Hz or more.

This is my RNetTask:

static portTASK_FUNCTION(RNetTask, pvParameters) {
  uint32_t cntr;
  uint8_t msgCntr;

  (void)pvParameters; /* not used */
  if (RAPP_SetThisNodeAddr(RNWK_ADDR_BROADCAST)!=ERR_OK) { /* set a default address */
    for(;;); /* "ERR: Failed setting node address" */
  }
  cntr = 0; /* initialize LED counter */
  msgCntr = 0; /* initialize message counter */
  appState = RNETA_INITIAL; /* initialize state machine state */
  for(;;) {
    Process(); /* process state machine */
    cntr++;
    if (cntr==100) { /* with an RTOS 10 ms/100 Hz tick rate, this is every second */
      LED3_On(); /* blink blue LED for 20 ms */
      RAPP_SendPayloadDataBlock(&msgCntr, sizeof(msgCntr), RAPP_MSG_TYPE_PING, RNWK_ADDR_BROADCAST, RPHY_PACKET_FLAGS_NONE);
      msgCntr++;
      cntr = 0;
      FRTOS1_vTaskDelay(20/portTICK_RATE_MS);
      LED3_Off(); /* blink blue LED */
    }
    FRTOS1_vTaskDelay(10/portTICK_RATE_MS);
  } /* for */
}

First, it assigns a node address for itself. I assign here the broadcast address as default. Then I initialize the counter variables and the state machine state (appState).

In the task loop I call Process(): this processes my state machine (more later). I’m using a counter to send every second a message, and I show this with a 20 ms blue LED blink.

Sending date is done with RAPP_SendPayloadDataBlock(): Here I send a ‘PING’ message with an 8bit message counter: 0, 1, 2, 3, 4, 5, and so on.

RAPP_SendPayloadDataBlock(&msgCntr, sizeof(msgCntr), RAPP_MSG_TYPE_PING, RNWK_ADDR_BROADCAST, RPHY_PACKET_FLAGS_NONE);

The first argument is the pointer to the message data (&msgCntr), followed by the size of the buffer (sizeof(msgCntr)). RAPP_MSG_TYPE_PING is the type of the message. RNWK_ADDR_BROADCAST is the destination address (I send it to every node in the network). The last argument are special flags, but I do not need any here, so I use RPHY_PACKET_FLAGS_NONE.

State Machine

The task processes a state machine, which has the following states:

typedef enum {
  RNETA_INITIAL, /* initialization state */
  RNETA_POWERUP, /* powered up the transceiver */
  RNETA_TX_RX /* ready to send and receive data */
} RNETA_State;

The corresponding state machine is very simple:

static void Process(void) {
  for(;;) {
    switch(appState) {
    case RNETA_INITIAL:
      appState = RNETA_POWERUP;
      continue;
      
    case RNETA_POWERUP:
      RadioPowerUp();
      appState = RNETA_TX_RX;
      break;
      
    case RNETA_TX_RX:
      (void)RADIO_Process();
      break;
 
    default:
      break;
    } /* switch */
    break; /* break for loop */
  } /* for */
}

From the initial state, it powers up the transceiver. Once the transceiver is powered, it its ready to send and receive data and processes the Radio messages. This is a very basic state machine: I use more complex ones for channel hopping, dynamically powering down the transceiver to save energy and so on. But for this tutorial I want to keep things simple.

Transceveiver Power-Up

If you read the nRF24L01+ data sheet carefully, you will notice that it needs 100 ms after power is applied until it is ready. I have seen some transceivers which needed even 120 or 130 ms, so I decided to wait 150 ms for all. Accessing the transceiver too early will create strange effects (it took me a while to realize that 😦 ). To wait the needed time, I use the following routine called from the above state machine:

static void RadioPowerUp(void) {
  /* need to ensure that we wait at least 100 ms (I use 150 ms here) after power-on of the transceiver */
  portTickType xTime;
 
  xTime = FRTOS1_xTaskGetTickCount();
  if (xTime<(150/portTICK_RATE_MS)) {
    /* not powered for 100 ms: wait until we can access the radio transceiver */
    xTime = (150/portTICK_RATE_MS)-xTime; /* remaining ticks to wait */
    FRTOS1_vTaskDelay(xTime);
  }
  (void)RADIO_PowerUp(); /* enable the transceiver */
}

As this is called in the context of the RTOS, I can use the current tick counter of the RTOS to find out if 150 ms have been passed. If not, I simply wait for the needed ticks, and then I call RADIO_PowerUp() which will access the transceiver and initialize it from power-up.

Message Handler

So far I can send messages, but how to receive a message? For this I’m using a message handler table which has a NULL pointer at the end, so I can add more handlers as needed before the NULL sentinel:

static const RAPP_MsgHandler handlerTable[] =
{
  RNETA_HandleRxMessage,
  NULL /* sentinel */
};

The RNet stack is informed about that table with the code we have seen earlier in RNETA_Init():

  if (RAPP_SetMessageHandlerTable(handlerTable)!=ERR_OK) { /* assign application message handler */
    for(;;); /* "ERR: failed setting message handler!" */
  }

Whenever the low-level radio driver receives a message, it is passed up the RNet stack, until it reaches that message handler table. Then each handler can inspect the message and process it.

For our tutorial application, I have implemented the handler as below:

static uint8_t RNETA_HandleRxMessage(RAPP_MSG_Type type, uint8_t size, uint8_t *data, RNWK_ShortAddrType srcAddr, bool *handled, RPHY_PacketDesc *packet) {
  (void)srcAddr;
  (void)packet;
  switch(type) {
    case RAPP_MSG_TYPE_PING: /* <type><size><data */
      *handled = TRUE;
      /* to be defined: do something with the ping, e.g blink a LED */
      LED2_On(); /* green LED blink */
      FRTOS1_vTaskDelay(20/portTICK_RATE_MS);
      LED2_Off();
      return ERR_OK;
    default:
      break;
  } /* switch */
  return ERR_OK;
}

Each handler receives the message type, the message size, the message payload data and who has sent the message (srcAddr). So all the message parts have been unpacked by the lower stack layers. But if you want to use the full packet, then it is passed as a pointer too. Finally there is a handled parameter: here I tell the caller that I was able to handle the message.

In the handler I check for the type (RAPP_MSG_TYPE_PING), and then I’m free to do anything with that message or message data. Here I’m simply blinking the green LED for 20 ms to show that I have received the ping message. To access the message counter I have passed in the payload, I can use the *data pointer.

main()

The last step is to call the initialization from main():

Calling from main()

Calling from main()

That should complete all the needed steps. Generate Code (if not already done), compile and build, and this should go without errors.

Running the Application

Running the application on the boards should get you some blinking LED’s:

  1. Each board sends a PING message every second, indicated with a blue LED blink:

    Blue LED for sending message

    Blue LED for sending message

  2. Whenever a board receives a PING message, it will blink the green LED:

    Green LED for received message

    Green LED for received message

Summary

With this tutorial I have added nRF24L01+ Transceiver support the Freedom FRDM-K64F board. The FRDM-K64F makes it really ease: solder a header, plugin the transceiver and add Processor Expert component to a project and I can communicate with another remote board. So I can build a network of sensor nodes very easily, and connect it to the internet, and so on. While this tutorial uses the FRDM-K64F board, you can easily do the same for any other board: all what you need is to connect the SPI pins and power the module. And of course add the software. Done :-).

This tutorial project is available on GitHub for Eclipse Kepler and the GNU ARM Eclipse.

Happy Transceiving 🙂

73 thoughts on “Tutorial: Nordic Semiconductor nRF24L01+ with the Freescale FRDM-K64F Board

  1. Hi Erich,

    Thanks for this great tutorial … It helped me alot to get started with the FRDM-K64F, but I still had some trouble setting up everything …

    Precon:
    I used an Eclipse Environment as described in your “Constructing a Classroom IDE with Eclipse for ARM” tutorial.

    First problem:
    When I added the FreeRTOS component and made the proposed changes, I got compile errors in the generated Processor Expert code (E.g “selected processor does not support Thumb mode `vldmiaeq r0!,{s16-s31}’).
    I was able to fix this by changing “Project Properties > C/C++ Build > Settings > Tool Settings > Target Processor > Float ABI “Librbray with FP (softfp)” and FPU Type “fpv4-sp-d16”.

    Second Problem:
    I was not able to add the 8MHz as the max frequency for the SynchroMaster component. Only after I changed the Clock Settings (Enabled RTC oscillator in clock sources and used the RTC oscillator in the Clock Source settings 0 for MCG and changed the frequencies to 95MHz) the 8MHz option was available.(Per default the maximum freq. of the FRDM-K64F was around 20MHz).

    Do you have any idea, what may have caused caused the problems and is this the correct way to fix them?
    Maybe any missing steps in my Eclipse setup?

    With kind regards

    Frank

    Like

    • Hi Frank,
      many thanks for your feedback, and indeed, I must have missed to describe some important steps and settings :-(. So nothing wrong on your side, it is mea culpa.
      I have added the missing steps in the following chapters: “Compiler Settings”, “CPU Clocks” and updated the screenshot with the FreeRTOS settings to have ‘floating point’ enabled too (otherwise the RTOS assumes no floating point operations are used).
      Thanks!

      Like

  2. Hi Erich,

    I want to test this project, but after import, I got a project with C++build/settings empty !!!

    Can you help me?

    Like

      • I import this project with CW10.6
        Should I install Eclipse Kepler? or can I convert this project to CW10.6?

        Like

        • The build plugins are not compatible. Best if you create a new Processor Expert CW project in 10.6, then you can copy-paste the components to your project. Then copy the application source files, and check the Events.c and call the application from main(). That’s it (I hope).

          Like

  3. Just wondering if you had any luck using USB on the K64F? I am having difficulties porting my USB applications from my K70f, K60, K20 to the K64F using the FSL USB stack.

    Like

    • No, I have had no luck with this neither. I believe something is missing in that stack to support these new Kinetis devices, and I got lost in the complexity of that USB peripheral on the K64F. I need to look at the Kinetis SDK USB stack instead: there I made some progress, but had no time to publish an article about it (yet). Oh well…

      Like

      • Thanks Erich! I will look into using the Kinetis SDK USB stack instead. BTW, very many thanks for putting this site together. It is really a treasure trove. I am coming from the 8/16 bit world of pic microcontrollers, and I was up and running in a few hours thanks to mcuoneclipse. So far, I have had no difficulties in making the transition, and I have been able to get answers to many of my questions from your site. Keep up the very excellent work!!
        .

        Like

      • Just wanted to follow up with you on this topic. After months of tinkering with USB on the kinetis platforms, I am now able to get USB working on the FRDM-k64f using the FSL USB 4.11 stack in CW. I was also able to get USB up and running in KDS using my own lightweight stack with the FRDM-K64F, FRDM-K22F, FRDM-K20D50M, TWR-K70F120M and TWR-K60D120M respectively.
        The main difference between USB on the K64f and most other kinetis family is the presence of a memory protection unit on the K64f. This must be disabled with the command MPU_CESR = 0 prior to initializing any USB stack.

        Like

  4. Pingback: Zumo Robot with WiFi and GPS | MCU on Eclipse

  5. Just recieved frdm-k64f board today, looking forward to try this out, the nordic-semiconductor-nrf24l01 are available locally here so… all nice.

    Like

  6. Hi, in trying to reproduce this great tutorial using Kinetis Design Studio, when I reach the configuration of nRF24L01 component, Processor Expert reports conflict errors when I try to select PTD4 pin for CSN1 and PTC18 for IRQ1:

    Selected value is in conflict with other configuration(s) property ‘SPI peripheral chip select(output) 0 or slave select(input)’ from component pin_mux Exclusive connection required by property ‘SPI peripheral chip select(output) 0 or slave select(input)’ from component pin_mux; Selected value is in conflict with other configuration property ‘SPI peripheral chip select(output) 0 or slave select(input)’ from component pin_mux, conflict in configuration of MUX bit-field of PORTD_PCR4 register. (Pin for I/O) K64F_nRF24L01p CSN1/Pin for I/O Processor Expert Problem

    Selected value is in conflict with other configuration(s) property ‘SPI peripheral chip select(output) 0 or slave select(input)’ from component pin_mux Exclusive connection required by property ‘SPI peripheral chip select(output) 0 or slave select(input)’ from component pin_mux; Selected value is in conflict with other configuration property ‘SPI peripheral chip select(output) 0 or slave select(input)’ from component pin_mux, conflict in configuration of MUX bit-field of PORTD_PCR4 register. (Pin for I/O) K64F_nRF24L01p BitIoLdd2/Pin for I/O Processor Expert Problem

    Selected value is in conflict with other configuration(s) property ‘Pin for I/O’ from component BitIoLdd2, property ‘General purpose IO pin 4’, property ‘Low-leakage wake-up channel 14’ Exclusive connection required by ; Selected value is in conflict with other configuration property ‘Pin for I/O’ from component BitIoLdd2, conflict in configuration of MUX bit-field of PORTD_PCR4 register. (SPI peripheral chip select(output) 0 or slave select(input)) K64F_nRF24L01p pin_mux/SPI peripheral chip select(output) 0 or slave select(input) Processor Expert Problem

    I followed all the instructions step by step but I am unable to find where the problem is.

    Any hint will be appreciated!

    Like

      • Hi Erich,

        thank you for your answer!

        Unfortunately I have already deleted the project with the intention to restart it from the beginning but until now I had no time to do it.

        However I successfully imported your original project and it compile correctly, so now I have a reference to compare my work with.

        I will post a comment when I discover where I was wrong in my first attempt.

        Thank you again for your support.

        Regards

        Francesco

        Like

  7. Pingback: Sensor and Communication Shield for Sumo Robot | MCU on Eclipse

  8. Pingback: BBQ Smoker Monitoring Robot | MCU on Eclipse

  9. Pingback: Cheap and Simple WiFi with ESP8266 for the FRDM Board | MCU on Eclipse

  10. Pingback: USB CDC with the FRDM-K64F, finally! | MCU on Eclipse

  11. Hi Eric
    Could you explain why you use the Nordic Semi module rather than a Kinetis chip with an internal transceiver? [i.e. MKW2xDxxx]
    I know that the Nordic Semi one is probably faster and possibly easier to use but it would be interesting to be able to do more or less the same thing using a single Kinetis chip.
    Thanks
    Mark

    Like

    • Hi Mark,
      there are several reasons to use the nRF24L01+ chip instead e.g. the KW2 or any other of this kind. First, such an integrated solution like the KW2 absolutely makes sense if PCB space or cost (in volume) are a concern. But otherwise I think an external transceiver is the prefered solution: you are independent of the microcontroller, you have better debug support (you can probe the signals) and know what is going on, and you can combine the best microcontroller with the best transceiver. When I started using the nRF, there were no KW2 available, or only on a TWR board. No small and inexpensive modules from anyone. The nRF is readily available from many sources, it is well known, used in many projects, and there are tons of forums/drivers available. And as you say: easier to use, and the specs are in some aspects even better than the KW variants. As you say, you can do more or less the same thing with the KW or the nRF. It boils down if you really need to have it in one device or not. For me using a dual-device approach worked out very well.

      Like

      • Eric
        I don’t know much about the 2.4GHz radio protocols but the KW2 supports ZiggBee and there is no mention of that in the Nordic Semi’s data sheets. Supposedly there are different protocols that can be usedin that band.
        Do you know whether a KW02 (using one of its modes/protocols) and a nRF24L01+ can work together?
        That is, have a K64 (for example) and nRF24L01+ at one and and a KW02 at the other?
        Regards
        Mark

        Like

        • Both the nRF24L01+ and KWx are using the 2.4 GHz band (as WiFi), but the are not compatible. The channel bands and the encoding on the channel are different and not compatible. ZigBee (and the KWx parts) are building on top of the IEEE802.15.4 PHY and MAC layers, while nRF24L01+ is using its own coding and no IEEE protocol. The nRF24L01+ is more like BLE (Bluetooth Low Energy) and you can use it in special mode to listen to BLE packets (but not sending it), at least I have seen articles about this. To answer your question: you cannot talk between a nRF24L01+ and a KW02.
          Erich

          Like

  12. Hello Eric

    I have also received a few of these modules and have connected them up to FRDM-K64 and FRDM-K22 boards (these both have the RF sockets on them, making them practical). In the case of the FRDM-K22 the resistor R52 needs to be removed otherwise the accelerometer IRQ output short circuits with the nRF24L01+ IRQ output. Initially I also didn’t know that the SPI used by the K64 doesn’t have the normal 4 deep FIFO, but only one, which caused some confusion.

    For this I used the Enhanced ShockBurst(TM) mode since it seems to generally allow maximum power efficiency and allows the transceiver to take over much of the low level details – also the TX enable signal can be left at ‘1’ and basically higher throughput efficiency

    This means that I have the K64 as PTX and the K22 as PRX with the K64 sending regular messages and the K22 receiving them, and optionally sending data back using the “ACK with payload” function.

    If I understand correctly you have also used these advanced modes so I am wondering whether you have any advice on the following?
    – Essentially I need to add fragment/deframent on the RF interface so that I can send larger messages (full size Ethernet).
    – Then I need to configure a bridge/router in the K64 end of the SW so that it passes IP traffic across the RF link (internally generated or from Ethernet)
    – The K22 has a TCP/IP stack and local web server so will use the RF link to send and receive this data.
    – The result is that the web server on the K22 can be contacted from the LAN that the K64 is on (using its routing/bridging function and the RF link)
    – There can be multiple K22s (or others) taking part, each with their own RF module (i.e. each contactably on their own IP address from the LAN)

    What I am mainly wondering about is what would be the best technique for this? If the K64 is in PTX mode it can periodically poll each K22 (send a dummy frame for example if there is no data to be sent at the moment) so that the K22s (PRX nodes) can send data from their output queue. The K64 can of course send at any time in this mode. This would need a fast polling rate to keep delays from the K22s low. Pipe 0 would be used for this and each K22 have its own unique 5 byte address.
    For broadcast transmissions from the K64 to the K22s I think that a second pipe where all K22s have the same 5 byte address may be suitable if the K64 sends such payloads with the auto ACK disabled (W_ACK_PAYLOAD_NOACK instead of W_TX_PAYLOAD).

    Since I don’t yet have any more experience with the RF modules, apart from checking the basic Enhanced ShockBurst(TM) mode [1Mbps with 500us timeout and 5 repetitions] between the K64 and K22, do you have any advice as to what may cause problems or could be done better?

    – hopefully the broadcast strategy is suitable (K64 sends in parallel to all K22s but without any guarantie, since no ACK) (?)
    – is the fixed PTX and all K22s as PRX (and polling) the best strategy or do people use some arbitration method so that the rolls can be swapped dynamically (?) to avoid un-necessary polling (and reduce power at the K64 when there is no activity?).

    At the moment I have only one FRDM-K22 so will need to wire up an adapter to some other board to try to verify the broadcast technique – if you confirm if it isn’t possible beforehand it would save some time 😉

    Regards

    Mark

    Like

    • Hi Mark,
      yes, I have used Enhanced Shockburst mode for my modules, as this greatly simplifies the protocol. From your question I understand that every module in your network will have its own address. Then should be generally ok. But you might need to add an additional layer of ACK message protocol to make sure that the messages get transmitted: the 5 retries might not be enough.
      The biggest problem I have with the nRF24L01+ modules is that they do not support a broadcast: it is not easily poosible to build up a network from scratch (with all modules having the same initial address): If you have say more than 3 or 5 modules listening, they all will answer with an ACK confusing the sender. But if you preprogram each module with a specific address, you should be fine.
      The other thing to consider: check the power consumption of your modules. I had received some which work, but draw always about 30 mA. There are some reports in the forums too. One theory is that they have an internal OTP, and if it gets somewhow corrupted, the module is always in RX/TX mode power-wise. And properly buffer the power supply of the module: fluktuations or spikes on the power supply will cause the modules to lock up.
      Good luck!
      Erich

      Like

      • Eric

        Thanks for the tips, which I will be considering during the work.
        I am also thinking about a method of automatically assigning addresses to the boards but initially I will be setting individual ones – they also need unique MAC addresses anyway, plus have a matching RF channel.
        In parallel to this I have to add a second Ethernet interface to the K64 (also SPI based with a Microchip ENC424J600 which I haven’t used before) so will have to make small steps at the beginning.

        Regards

        Mark

        Like

    • Hello,

      I stumbled on this site while searching about the SPI FIFO.
      Actually, according to the MK64FN1M0VLL12 manual (page 159), SPI0 has a 4 Word FIFO. However, SPI1 & 2 only 1.

      Regards,
      Gunter

      Like

      • hi Erich,
        I am trying this project from git hub. Ever since you posted this project Freescale has updated SDK and KDS to new versions. I am getting following error
        make: *** No rule to make target `C:/Freescale/KDS_2.0.0/eclipse/ProcessorExpert/lib/Kinetis/pdd2/MK64FN1M0LL12/system/CPU_Init.c’, needed by `Static_Code/System/CPU_Init.o’. Stop.
        make: *** No rule to make target `C:/Freescale/KDS_1.0.1/eclipse/ProcessorExpert/lib/Kinetis/pdd2/MK64FN1M0LQ12/system/CPU_Init.c’, needed by `Static_Code/System/CPU_Init.o’. Stop.
        I am using KDS_3.0 and KSDK 1.3.0
        Where and what changes do you suggest to build this project with latest versions properly?

        Like

        • Hi Ammad,
          that project is for Eclipse Mars or Luna, not for KDS. Plus this project is not using the Kinetis SDK. And given the make messages, you are using a mixture of KDS v2.0.0 and KDS v1.0.1? I checked again the project on GitHub, and it builds fine for me? But it might be that the Static_Code folder is not present for you? I will add it to the project just in case.
          I will post the necessary changes for Eclipse MARS today too (just in case this matters).

          Like

  13. Pingback: Infotronic WS2014 Sumo Robots are Ready! | MCU on Eclipse

  14. Pingback: Kinetis Drone: Frame Construction with Graupner Race Copter Alpha 250 Q | MCU on Eclipse

  15. Hi Erich. Its working fine now. Thanks for the help.
    Where do you configure the addresses for the board? Could you please point me to the file and function?

    Like

    • Hi Erich,
      Sorry for cluttering your page. I was wondering if you have done any such example with KSDK? That way we could utilize the existing facilities like lwIP and other stuff. It would be fun to do so. Its a pity that KSDK doesnt include examples for nRF24L01. Freescale should consider adding it to their library given they provide special space for the module.

      Like

      • No, I don’t have an example with the KSDK. I had an example working with the SDK v1.1, then SDK v1.2 came out and everything was not compatible. I ported it to v1.2 and when done, SDK v1.3 came out and again everything was incompatible and stopped working. I stopped spending my time with it. I quickly checked if I still have that SDK project available, but it seems I have removed it. So at the end, it was much easier to use Processor Expert, especially because the drivers keep being compatible. But at the end I think it is a question of personal taste, and how much efforts you are willing to spend. I hope that with the next version of the SDK the API will stabilize so I can move more and more projects to the Kinetis SDK.

        Like

      • Thanks for the help.
        I am still not getting green LED blinking. I was wondering to come up with a way to debug the RF module. I want to read and write the registers of RF module with custom messages to make sure the SPI messages are being correctly written on RF module. I have got blue LEDs blinking but never turn green. After reading the code I am not sure Blue LED blinking means for sure that the RF module has transmitted something. It just means board has called that transmission function. I want something which can assure me that the RF module is working, the only way seems to me is start reading the module’s registers.
        We know that there are certain commands to read write the registers. Could you tell me which function is doing that?

        Like

        • It could be that your wiring is not correct. Or that you are using a fake nRF24L01+ module (I have myself received some cheap modules from China which did not work at all).
          I recommend that you hook up a logic analyzer to the signals to the transceiver so you see what is going on.

          For reading/writing the transceiver registers: the nRF24L01 (RF1) component has read and write functions implemented.

          Like

      • H Erich, I would like your expert opinion on the following data.
        I tried this:
        LED3_On(); /* blink blue LED for 20 ms */
        RAPP_SendPayloadDataBlock(&msgCntr, sizeof(msgCntr), RAPP_MSG_TYPE_PING, RNWK_ADDR_BROADCAST, RPHY_PACKET_FLAGS_NONE);
        msgCntr++;
        cntr = 0;
        FRTOS1_vTaskDelay(20/portTICK_RATE_MS);
        LED3_Off(); /* blink blue LED */
        x = RF1_ReadRegister(0x08);
        x = RF1_ReadRegister(0x00);
        x = RF1_ReadRegister(0x01);
        x = RF1_ReadRegister(0x02);
        x = RF1_ReadRegister(0x03);
        x = RF1_ReadRegister(0x04);
        Register 0x08 is the is the OBSERVE_TX register which tells you if something has been transmitted. (Correct me if i am wrong).

        For the sake of being sure I read the values of several registers.
        I get the following values:
        0x00 = 0xE
        0x01 = 0x1
        0x02= 0x1
        0x03= 0x03
        0x04 = 0x2F
        0x08 = 0x00

        I bought 5 RF modules in a single batch. Seems like none of them has a working RF. I feel I can safely declare all 5 modules as faulty. What do you think?

        Like

        • I really don’t knwo what is wrong with your modules. If you got counterfeit modules, then very likely all of them will be counterfeit. I received once a batch of modules which were not trimmed: the antennas/sending frequency where several MHz off the center bands, being able to barely to communicate. I heard that in China they take the ‘bad devices’ which do not pass the quality tests of Nordic and then sell the devices as low cost ones. For sure I had received such a bad badge from a vendor.
          Have you checked the interrupt line of the module if it is behaving properly?

          Like

      • No i havent checked the interrupt line. On the packaging it says nRF24L01+ but when I magnified the chip on the module it says Si24R1.

        Did you manage to make those cheap modules work? Any work around for them?

        Like

    • The transceiver address is specifed in Generated_Code\radio.c:
      static const uint8_t RADIO_TADDR[5] = {0x11, 0x22, 0x33, 0x44, 0x55}; /* device address, as specified in the properties */
      It is configured in the settings of the RNet component.
      So you need the files to be generated with Processor Expert as the generated files are not pushed on GitHub.

      I hope this helps,
      Erich

      Like

      • Hi Erich,
        Thanks for the help. If you still have projects from previous SDK’s working could you email me the zip file? That would be really helpful. I have tried including processor expert as well as SDK into a single project but that doesnt seem to work.

        Like

        • It seems I do not have them any more: I have deleted them as with the SDK changes they code was not compiling any more, and it was too much pain to move from one SDK version to another :-(.

          Like

      • Hi,
        I apologize for bothering you again and again. I am new to this board stuff. I have downloaded build and loaded binaries on to two board. No changes in the code yet. Only Blue LEDs are blinking. I have marked break points on SM1_OnRxChar and SM1_OnTxChar. Both functions are repatedly hit but no green LED blinks. Could you please tell me what have I not configured?
        I was also wondering what do you recommend to print messages on serial com since PRINTF from SDK is not not working in this project. I want to send custom data on boards what functions in this stack should i call?

        Again Thanks for for your help and time. I found your forum really helpful since started with FRDM boards

        Like

    • Thanks Erich,

      I have tried reading and writing registers. Seems like module is reading and writing. Did your fake module read or write on registers? I do not have a logic analyzer so I am relying on reading the registers of module in the code.
      If the module is reading and writing that means RF is is fine I guess. Whats your opinion on this? I have got my modules from China. On the packing it says SEED STUDIO INNOVATE with China. Was your vendor same?

      Like

      • Yes, I was able to read/write to the modules, but they were not sending or receiving anything.
        Reading or writing registers only tells that you can access the transceiver, but not if the RF is working.
        I don’t have the modules with me, so I cannot tell you what was written on them.

        Like

      • Thanks a lot Erich. That was really helpful. I might check with a field detector if they are sending any RF signal. It was driving me crazy now as the registers were reading all fine.

        Like

  16. Pingback: How to Add Bluetooth Low Energy (BLE) Connection to ARM Cortex-M | MCU on Eclipse

  17. Pingback: nRF24L01+ 2.4 GHz Wireless Connectivity with the tinyK20 Board | MCU on Eclipse

  18. Hi Erich, I want to use a nRF24L01+ on a 8bit freescale microcontroller (HCS08GT60), off course I won´t use FreeRTOS, then, Do you have some sample of How can I use the nRF24L01 PE component? thank you.

    Like

  19. Pingback: Disabling EzPort on NXP Kinetis to Solve Power-On Issues | MCU on Eclipse

  20. Hi Erich,

    thanks a lot for the great tutorial! It helped me a lot to understand the involved workflow.

    Since I am using the K66F without processor expert support, I want to translate your demo to a generic FreeRTOS environment created using KSDK 2.2.

    To start with, I have set up the board_to_board FreeRTOS SPI example from NXP and changed the SPIBase of the master to also use the J6 header. If I now connect cables between the two boards, communication works fine.

    Unfortunately, I am now not quite sure what additional steps I need to take to switch from wired to wireless communication. Could you perhaps give me a brief hint what needs to be done?

    Thanks a lot!
    Florian

    Like

    • Hi Florian,
      are you trying to communicate between two FRDM-K66F boards that way? You cannot directly send SPI data between the boards using the nRF24L01+ or any other communication protocol. What you need is to define your own gateway protocol which sends the data from one side and decodes it from the other side. Be aware that SPI is synchronous, and the wireless connection is asynchronous with some extra delays.

      Like

  21. how cam i get the data, any time i try to print “data” whit ConsoleIO in RNETA_HandleRxMessage, the code send me to Cpu_Interrupt =[….. how can i get the mensage, where it is ?

    static uint8_t RNETA_HandleRxMessage(RAPP_MSG_Type type, uint8_t size, uint8_t *data, RNWK_ShortAddrType srcAddr, bool *handled, RPHY_PacketDesc *packet) {
    (void)srcAddr;
    (void)packet;
    switch(type) {
    case RAPP_MSG_TYPE_PING: /* <data */
    *handled = TRUE;
    /* to be defined: do something with the ping, e.g blink a LED */
    LED1_Neg();
    FRTOS1_vTaskDelay(20/portTICK_RATE_MS);
    printf("%d\n",data[0]);
    return ERR_OK;
    default:
    break;
    } /* switch */
    return ERR_OK;
    }

    Like

  22. Hi Erich,

    I am having an issue with RNet_App.c that I was hoping I could get your advice on, specifically the portTICK_RATE_MS variable. On lines 36, 56, and 106 I am given the error:
    ‘portTICK_RATE_MS’ undeclared (first use in this function)
    However on line 109 I have no issues whatsoever. Line 53 gives me the error:
    unknown type name ‘portTickType’.
    I am very new to this stuff so I apologize in advance for any poor details.

    Like

    • Hi Kyle,
      the reason for the error is that these examples are rather old and not maintained. Instead I recommend you use KDS (Kinetis Design Studio) if you want to use Processor Expert. There is the same example for it available here:
      https://github.com/ErichStyger/mcuoneclipse/tree/master/Examples/KDS/FRDM-K64F120M/FRDM-K64F_nRF24

      The error is because later FreeRTOS has moved portTICK_RATEM_MS to ‘legacy’. And other types are now TickType_t instead of portTickType. So you would have to update the sources (or simply switch to using KDS and its projects as I have updated it there).
      Sorry for the inconvenience,
      Erich

      Like

      • I appreciate the quick response. I am actually using Kinetis but the NRF24L01 + PA + LNA (not sure if it matters), but using the source files of your link above solved that issue and gave some new ones (fun!). So I followed your hardware steps to a T but some default values I saw were different in my Kinetis. I left them alone figuring your yellow block settings were more crucial. My issue now is that my processor expert is not generating some .h and .c files e.g. BitIoLdd(6-10), KEY1, KIN1, about six total. I am going to start a new project matching as many of your values in the hardware setup as I can and hope that somehow it will generate the missing files. Thank you again and if any reason comes to mind about the missing generated codes I’d appreciate any future help.

        My end goal is to actually have an Arduino be the receiver. I want the K64 to send input values from a dip switch via the NRF24 to an Arduino and have the Arduino control the stepper motor based on the switch settings.

        Like

What do you think?

This site uses Akismet to reduce spam. Learn how your comment data is processed.