Library 17- nRF24L01+ for STM32F4
17th library is here. I will show how to basic communicate with 2 nRF24L01+ RF transceivers.
The Nordic nRF24L01+ is a highly integrated, ultra low power (ULP) 2Mbps RF transceiver IC for the 2.4GHz ISM (Industrial, Scientific and Medical) band. With peak RX/TX currents lower than 14mA, a sub μA power down mode, advanced power management, and a 1.9 to 3.6V supply range, the nRF24L01+ provides a true ULP solution enabling months to years of battery life from coin cell or AA/AAA batteries. The Enhanced ShockBurst™ hardware protocol accelerator offloads time critical protocol functions from the application microcontroller enabling the implementation of advanced and robust wireless connectivity with low cost 3rd-party microcontrollers.
The Nordic nRF24L01+ integrates a complete 2.4GHz RF transceiver, RF synthesizer, and baseband logic including the Enhanced ShockBurst™ hardware protocol accelerator supporting a high-speed SPI interface for the application controller. No external loop filter, resonators, or VCO varactor diodes are required, only a low cost ±60ppm crystal, matching circuitry, and antenna.
The nRF24L01+ is available in a compact 20-pin 4 x 4mm QFN package.
nRF24L01+ has 6 data pypes. This means, that can receive data simultaneously from 5 nRF24L01+. My library uses only 1 data pype, so 2 nRF24L01s can be connected together and communicate. Every of them has an unique 5bytes long address, which is software selectable.
For example below, i used nRF24L01+ modules from ebay (link), their pinout is below
NRF24L01+ | Discovery board | Description |
---|---|---|
GND | GND | Ground |
VCC | 3.3V | 3.3V |
CE | PD8 | RF activated pin |
CSN | PD7 | SPI3 Pinspack 2 CSN pin |
SCK | PC10 | SPI3 Pinspack 2 SCK pin |
MOSI | PC12 | SPI3 Pinspack 2 MOSI pin |
MISO | PC11 | SPI3 Pinspack 2 MISO pin |
IRQ | Not used | Interrupt pin. Goes low when active |
nRF24L01+ Library
Features
- Support for nRF24L01+
- Max 32bytes of payload size
- User selectable Own and TX address
- up to 15 auto retransmissions with auto ACK
- Get transmission status (sent ok, message lost, still sending)
- Channel selectable from 0 to 125 (2.4 to 2.525GHz)
- Data rate selectable, 2Mbps, 1Mbps or 250kbps
- Output power selectable, -18dBm, -12dBm, -6dBm or 0dBm
- Interrupt pin activated on nRF24L01+
Future planing
In near future I’m planning to make a nRF24L01+ wireless network.
Library Dependencies
- CMSIS
- STM32F4xx
- STM32F4xx RCC
- STM32F4xx GPIO
- STM32F4xx SPI
- TM
- TM SPI
- TM GPIO
- defines.h
- TM SPI
Functions and enumerations
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 |
/** * @defgroup TM_NRF24L01P_Typedefs * @brief Library Typedefs * @{ */ /** * @brief Transmission status enumeration */ typedef enum { TM_NRF24L01_Transmit_Status_Lost = 0x00, /*!< Message is lost, reached maximum number of retransmissions */ TM_NRF24L01_Transmit_Status_Ok = 0x01, /*!< Message sent successfully */ TM_NRF24L01_Transmit_Status_Sending = 0xFF /*!< Message is still sending */ } TM_NRF24L01_Transmit_Status_t; /** * @brief Data rate enumeration */ typedef enum { TM_NRF24L01_DataRate_2M, /*!< Data rate set to 2Mbps */ TM_NRF24L01_DataRate_1M, /*!< Data rate set to 1Mbps */ TM_NRF24L01_DataRate_250k /*!< Data rate set to 250kbps */ } TM_NRF24L01_DataRate_t; /** * @brief Output power enumeration */ typedef enum { TM_NRF24L01_OutputPower_M18dBm, /*!< Output power set to -18dBm */ TM_NRF24L01_OutputPower_M12dBm, /*!< Output power set to -12dBm */ TM_NRF24L01_OutputPower_M6dBm, /*!< Output power set to -6dBm */ TM_NRF24L01_OutputPower_0dBm /*!< Output power set to 0dBm */ } TM_NRF24L01_OutputPower_t; /* Clear interrupt flags */ #define NRF24L01_CLEAR_INTERRUPTS do { TM_NRF24L01_WriteRegister(0x07, 0x70); } while (0) /* Gets interrupt status from device */ #define NRF24L01_GET_INTERRUPTS TM_NRF24L01_GetStatus() /* Interrupt masks */ #define NRF24L01_IRQ_DATA_READY 0x40 /*!< Data ready for receive */ #define NRF24L01_IRQ_TRAN_OK 0x20 /*!< Transmission went OK */ #define NRF24L01_IRQ_MAX_RT 0x10 /*!< Max retransmissions reached, last transmission failed */ /** * @} */ /** * @defgroup TM_NRF24L01P_Functions * @brief Library Functions * * Here are listed very basic functions to work with NRF modules * * @{ */ /** * @brief Initializes NRF24L01+ module * @param channel: channel you will use for communication, from 0 to 125 eg. working frequency from 2.4 to 2.525 GHz * @param payload_size: maximum data to be sent in one packet from one NRF to another. * @note Maximal payload size is 32bytes * @retval 1 */ uint8_t TM_NRF24L01_Init(uint8_t channel, uint8_t payload_size); /** * @brief Sets own address. This is used for settings own id when communication with other modules * @note "Own" address of one device must be the same as "TX" address of other device (and vice versa), * if you want to get successful communication * @param *adr: Pointer to 5-bytes length array with address * @retval None */ void TM_NRF24L01_SetMyAddress(uint8_t* adr); /** * @brief Sets address you will communicate with * @note "Own" address of one device must be the same as "TX" address of other device (and vice versa), * if you want to get successful communication * @param *adr: Pointer to 5-bytes length array with address * @retval None */ void TM_NRF24L01_SetTxAddress(uint8_t* adr); /** * @brief Gets number of retransmissions needed in last transmission * @param None * @retval Number of retransmissions, between 0 and 15. */ uint8_t TM_NRF24L01_GetRetransmissionsCount(void); /** * @brief Sets NRF24L01+ to TX mode * @note In this mode is NRF able to send data to another NRF module * @param None * @retval None */ void TM_NRF24L01_PowerUpTx(void); /** * @brief Sets NRF24L01+ to RX mode * @note In this mode is NRF able to receive data from another NRF module. * This is default mode and should be used all the time, except when sending data * @param None * @retval None */ void TM_NRF24L01_PowerUpRx(void); /** * @brief Sets NRF24L01+ to power down mode * @note In power down mode, you are not able to transmit/receive data. * You can wake up device using @ref TM_NRF24L01_PowerUpTx() or @ref TM_NRF24L01_PowerUpRx() functions * @param None * @retval None */ void TM_NRF24L01_PowerDown(void); /** * @brief Gets transmissions status * @param None * @retval Transmission status. Return is based on @ref TM_NRF24L01_Transmit_Status_t enumeration */ TM_NRF24L01_Transmit_Status_t TM_NRF24L01_GetTransmissionStatus(void); /** * @brief Transmits data with NRF24L01+ to another NRF module * @param *data: Pointer to 8-bit array with data. * Maximum length of array can be the same as "payload_size" parameter on initialization * @retval None */ void TM_NRF24L01_Transmit(uint8_t *data); /** * @brief Checks if data is ready to be read from NRF24L01+ * @param None * @retval Data ready status: * - 0: No data available for receive in bufferReturns * - > 0: Data is ready to be collected */ uint8_t TM_NRF24L01_DataReady(void); /** * @brief Gets data from NRF24L01+ * @param *data: Pointer to 8-bits array where data from NRF will be saved * @retval None */ void TM_NRF24L01_GetData(uint8_t *data); /** * @brief Sets working channel * @note Channel value is just an offset in units MHz from 2.4GHz * For example, if you select channel 65, then operation frequency will be set to 2.465GHz. * @param channel: RF channel where device will operate * @retval None */ void TM_NRF24L01_SetChannel(uint8_t channel); /** * @brief Sets RF parameters for NRF24L01+ * @param DataRate: Data rate selection for NRF module. This parameter can be a value of @ref TM_NRF24L01_DataRate_t enumeration * @param OutPwr: Output power selection for NRF module. This parameter can be a value of @ref TM_NRF24L01_OutputPower_t enumeration * @retval None */ void TM_NRF24L01_SetRF(TM_NRF24L01_DataRate_t DataRate, TM_NRF24L01_OutputPower_t OutPwr); /** * @brief Gets NRLF+ status register value * @param None * @retval Status register from NRF */ uint8_t TM_NRF24L01_GetStatus(void); /* Private */ void TM_NRF24L01_WriteRegister(uint8_t reg, uint8_t value); /** * @} */ |
Example
In example, I used 2 nRF24L01+ modules to communicate. One was connected to my STM32F4 discovery, second to STM32F429.
In example below, “transmitter” sends 32bytes of data to receiver and starts counting time. If sent was successfully, data will be returned from receiver. Time needed for that is displayed on Terminal with USART.
Code has comments, so I think it will be understandable.
Bottom are use “transmitter” and “receiver”, but remember: nRF24L01+ can be both, transmitter and receiver!
Make sure, that addresses match each other. On one side “TX” address is on other side “My” address.
Transmitter code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 |
/** * Keil project for NRF24L01+ transceiver * * Transmitter code * * Before you start, select your target, on the right of the "Load" button * * @author Tilen Majerle * @email tilen@majerle.eu * @website http://stm32f4-discovery.net * @ide Keil uVision 5 * @packs STM32F4xx Keil packs version 2.2.0 or greater required * @stdperiph STM32F4xx Standard peripheral drivers version 1.4.0 or greater required */ /* Include core modules */ #include "stm32f4xx.h" /* Include my libraries here */ #include "defines.h" #include "tm_stm32f4_nrf24l01.h" #include "tm_stm32f4_disco.h" #include "tm_stm32f4_delay.h" #include "tm_stm32f4_usart.h" #include <stdio.h> /* My address */ uint8_t MyAddress[] = { 0xE7, 0xE7, 0xE7, 0xE7, 0xE7 }; /* Receiver address */ uint8_t TxAddress[] = { 0x7E, 0x7E, 0x7E, 0x7E, 0x7E }; uint8_t dataOut[32], dataIn[32]; int main(void) { TM_NRF24L01_Transmit_Status_t transmissionStatus; char str[40]; /* Initialize system */ SystemInit(); /* Initialize system and Delay functions */ TM_DELAY_Init(); /* Initialize onboard leds */ TM_DISCO_LedInit(); /* Initialize USART, TX: PB6, RX: PB7 */ TM_USART_Init(USART1, TM_USART_PinsPack_2, 115200); /* Initialize NRF24L01+ on channel 15 and 32bytes of payload */ /* By default 2Mbps data rate and 0dBm output power */ /* NRF24L01 goes to RX mode by default */ TM_NRF24L01_Init(15, 32); /* Set 2MBps data rate and -18dBm output power */ TM_NRF24L01_SetRF(TM_NRF24L01_DataRate_2M, TM_NRF24L01_OutputPower_M18dBm); /* Set my address, 5 bytes */ TM_NRF24L01_SetMyAddress(MyAddress); /* Set TX address, 5 bytes */ TM_NRF24L01_SetTxAddress(TxAddress); /* Reset counter */ TM_DELAY_SetTime(2001); while (1) { /* Every 2 seconds */ if (TM_DELAY_Time() > 2000) { /* Fill data with something */ sprintf((char *)dataOut, "abcdefghijklmnoszxABCDEFCBDA"); /* Display on USART */ TM_USART_Puts(USART1, "pinging: "); /* Reset time, start counting microseconds */ TM_DELAY_SetTime(0); /* Transmit data, goes automatically to TX mode */ TM_NRF24L01_Transmit(dataOut); /* Turn on led to indicate sending */ TM_DISCO_LedOn(LED_GREEN); /* Wait for data to be sent */ do { transmissionStatus = TM_NRF24L01_GetTransmissionStatus(); } while (transmissionStatus == TM_NRF24L01_Transmit_Status_Sending); /* Turn off led */ TM_DISCO_LedOff(LED_GREEN); /* Go back to RX mode */ TM_NRF24L01_PowerUpRx(); /* Wait received data, wait max 100ms, if time is larger, then data were probably lost */ while (!TM_NRF24L01_DataReady() && TM_DELAY_Time() < 100); /* Format time */ sprintf(str, "%d ms", TM_DELAY_Time()); /* Show ping time */ TM_USART_Puts(USART1, str); /* Get data from NRF2L01+ */ TM_NRF24L01_GetData(dataIn); /* Check transmit status */ if (transmissionStatus == TM_NRF24L01_Transmit_Status_Ok) { /* Transmit went OK */ TM_USART_Puts(USART1, ": OK\n"); } else if (transmissionStatus == TM_NRF24L01_Transmit_Status_Lost) { /* Message was LOST */ TM_USART_Puts(USART1, ": LOST\n"); } else { /* This should never happen */ TM_USART_Puts(USART1, ": SENDING\n"); } } } } |
Receiver code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 |
/** * Keil project for NRF24L01+ transceiver * * Receiver code * * Before you start, select your target, on the right of the "Load" button * * @author Tilen Majerle * @email tilen@majerle.eu * @website http://stm32f4-discovery.net * @ide Keil uVision 5 */ /* Include core modules */ #include "stm32f4xx.h" /* Include my libraries here */ #include "defines.h" #include "tm_stm32f4_nrf24l01.h" #include "tm_stm32f4_disco.h" #include "tm_stm32f4_delay.h" #include "tm_stm32f4_usart.h" #include <stdio.h> /* Receiver address */ uint8_t TxAddress[] = { 0xE7, 0xE7, 0xE7, 0xE7, 0xE7 }; /* My address */ uint8_t MyAddress[] = { 0x7E, 0x7E, 0x7E, 0x7E, 0x7E }; uint8_t dataOut[32], dataIn[32]; int main(void) { TM_NRF24L01_Transmit_Status_t transmissionStatus; /* Initialize system */ SystemInit(); /* Initialize system and Delay functions */ TM_DELAY_Init(); /* Initialize onboard leds and button */ TM_DISCO_LedInit(); /* Initialize USART, TX: PB6, RX: PB7 */ TM_USART_Init(USART1, TM_USART_PinsPack_2, 115200); /* Initialize NRF24L01+ on channel 15 and 32bytes of payload */ /* By default 2Mbps data rate and 0dBm output power */ /* NRF24L01 goes to RX mode by default */ TM_NRF24L01_Init(15, 32); /* Set RF settings, Data rate to 2Mbps, Output power to -18dBm */ TM_NRF24L01_SetRF(TM_NRF24L01_DataRate_2M, TM_NRF24L01_OutputPower_M18dBm); /* Set my address, 5 bytes */ TM_NRF24L01_SetMyAddress(MyAddress); /* Set TX address, 5 bytes */ TM_NRF24L01_SetTxAddress(TxAddress); while (1) { /* If data is ready on NRF24L01+ */ if (TM_NRF24L01_DataReady()) { /* Get data from NRF24L01+ */ TM_NRF24L01_GetData(dataIn); /* Send it back, automatically goes to TX mode */ TM_NRF24L01_Transmit(dataIn); /* Start send */ TM_DISCO_LedOn(LED_GREEN); /* Wait for data to be sent */ do { transmissionStatus = TM_NRF24L01_GetTransmissionStatus(); } while (transmissionStatus == TM_NRF24L01_Transmit_Status_Sending); /* Send done */ TM_DISCO_LedOff(LED_GREEN); /* Go back to RX Mode */ TM_NRF24L01_PowerUpRx(); } } } |
Projects available on Github, download library below.
nRF24L01+ 2.4GHz transceiver
On my Github you will also found examples with interrupts for send and receive data.
Recent comments