mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
Initial import of nrf24l01p lowlevel functions
This commit is contained in:
parent
50ec8d10c9
commit
d8a26d5aa6
@ -4,6 +4,9 @@ endif
|
||||
ifneq (,$(filter netdev_802154,$(USEMODULE)))
|
||||
DIRS += netdev/802154
|
||||
endif
|
||||
ifneq (,$(filter nrf24l01p,$(USEMODULE)))
|
||||
DIRS += nrf24l01p
|
||||
endif
|
||||
|
||||
DIRS += $(dir $(wildcard $(addsuffix /Makefile, ${USEMODULE})))
|
||||
|
||||
|
@ -22,3 +22,6 @@ endif
|
||||
ifneq (,$(filter l3g4200d,$(USEMODULE)))
|
||||
USEMODULE_INCLUDES += $(RIOTBASE)/drivers/l3g4200d/include
|
||||
endif
|
||||
ifneq (,$(filter nrf24l01p,$(USEMODULE)))
|
||||
USEMODULE_INCLUDES += $(RIOTBASE)/drivers/nrf24l01p/include
|
||||
endif
|
||||
|
586
drivers/include/nrf24l01p.h
Normal file
586
drivers/include/nrf24l01p.h
Normal file
@ -0,0 +1,586 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Hamburg University of Applied Sciences
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser General
|
||||
* Public License v2.1. See the file LICENSE in the top level directory for more
|
||||
* details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup drivers_nrf24l01p NRF24L01+ Driver Interface
|
||||
* @ingroup drivers
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief Low-level driver for nrf24l01+ transceiver
|
||||
*
|
||||
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
|
||||
* @author Peter Kietzmann <peter.kietzmann@haw-hamburg.de>
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __NRF24L01P_H
|
||||
#define __NRF24L01P_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include "periph/gpio.h"
|
||||
#include "periph/spi.h"
|
||||
|
||||
/**
|
||||
* @brief Structure that represents the hardware setup of the nrf24l01+ transceiver.
|
||||
*/
|
||||
typedef struct {
|
||||
spi_t spi; /**< SPI device to initialize */
|
||||
gpio_t ce; /**< GPIO pin to initialize as chip enable */
|
||||
gpio_t cs; /**< GPIO pin to initialize as chip select */
|
||||
gpio_t irq; /**< GPIO pin to initialize as interrupt request */
|
||||
int listener; /**< Place to store an ID in */
|
||||
} nrf24l01p_t;
|
||||
|
||||
/**
|
||||
* @brief Defines the address width of the nrf24l01+ transceiver.
|
||||
*/
|
||||
typedef enum {
|
||||
NRF24L01P_AW_3BYTE, /**< address width is 3 Byte */
|
||||
NRF24L01P_AW_4BYTE, /**< address width is 4 Byte */
|
||||
NRF24L01P_AW_5BYTE /**< address width is 5 Byte */
|
||||
} nrf24l01p_aw_t;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Defines the RF datarate.
|
||||
*/
|
||||
typedef enum {
|
||||
NRF24L01P_DR_250KBS,/**< datarate is 250 kbps */
|
||||
NRF24L01P_DR_1MBS, /**< datarate is 1 Mbps */
|
||||
NRF24L01P_DR_2MBS /**< datarate is 2 Mbps */
|
||||
} nrf24l01p_dr_t;
|
||||
|
||||
/**
|
||||
* @brief Defines the RF power level.
|
||||
*/
|
||||
typedef enum {
|
||||
NRF24L01P_PWR_N18DBM = 0, /**< power is -18dBm */
|
||||
NRF24L01P_PWR_N12DBM, /**< power is -12dBm */
|
||||
NRF24L01P_PWR_N6DBM, /**< power is - 6dBm */
|
||||
NRF24L01P_PWR_0DBM /**< power is 0dBm */
|
||||
} nrf24l01p_pwr_t;
|
||||
|
||||
/**
|
||||
* @brief Defines the datapipe on which the receiver searches for packets.
|
||||
*/
|
||||
typedef enum {
|
||||
NRF24L01P_PIPE0 = 0,/**< RX pipe 0 */
|
||||
NRF24L01P_PIPE1, /**< RX pipe 1 */
|
||||
NRF24L01P_PIPE2, /**< RX pipe 2 */
|
||||
NRF24L01P_PIPE3, /**< RX pipe 3 */
|
||||
NRF24L01P_PIPE4, /**< RX pipe 4 */
|
||||
NRF24L01P_PIPE5 /**< RX pipe 5 */
|
||||
} nrf24l01p_rx_pipe_t;
|
||||
|
||||
/**
|
||||
* @brief Defines the error detection encoding scheme for the nrf24l01p transceiver.
|
||||
*/
|
||||
typedef enum {
|
||||
NRF24L01P_CRC_1BYTE = 0, /**< encoding scheme generates 1 Byte redundancy */
|
||||
NRF24L01P_CRC_2BYTE, /**< encoding scheme generates 2 Bytes redundancy */
|
||||
} nrf24l01p_crc_t;
|
||||
|
||||
/**
|
||||
* @brief Defines the automatic retransmission delay defined from end of transmission
|
||||
* to start of next treansmission.
|
||||
*/
|
||||
typedef enum {
|
||||
NRF24L01P_RETR_250US = 0, /**< retransmit delay is 250us */
|
||||
NRF24L01P_RETR_500US, /**< retransmit delay is 500us */
|
||||
NRF24L01P_RETR_750US, /**< retransmit delay is 750us */
|
||||
NRF24L01P_RETR_1000US, /**< retransmit delay is 1000us */
|
||||
NRF24L01P_RETR_1250US, /**< retransmit delay is 1250us */
|
||||
NRF24L01P_RETR_1500US, /**< retransmit delay is 1500us */
|
||||
NRF24L01P_RETR_1750US, /**< retransmit delay is 1750us */
|
||||
NRF24L01P_RETR_2000US, /**< retransmit delay is 2000us */
|
||||
NRF24L01P_RETR_2250US, /**< retransmit delay is 2250us */
|
||||
NRF24L01P_RETR_2500US, /**< retransmit delay is 2500us */
|
||||
NRF24L01P_RETR_2750US, /**< retransmit delay is 2750us */
|
||||
NRF24L01P_RETR_3000US, /**< retransmit delay is 3000us */
|
||||
NRF24L01P_RETR_3250US, /**< retransmit delay is 3250us */
|
||||
NRF24L01P_RETR_3500US, /**< retransmit delay is 3500us */
|
||||
NRF24L01P_RETR_3750US, /**< retransmit delay is 3750us */
|
||||
NRF24L01P_RETR_4000US, /**< retransmit delay is 4000us */
|
||||
} nrf24l01p_retransmit_delay_t;
|
||||
|
||||
/**
|
||||
* @brief Defines states for the nrf24l01+ transceiver
|
||||
*/
|
||||
typedef enum {
|
||||
RCV_PKT_NRF24L01P = 0, /**< transceiver received data */
|
||||
} nrf24l01p_rx_event_t ;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Read one register of the nrf24l01+ transceiver.
|
||||
*
|
||||
* @param[in] dev Transceiver device to use.
|
||||
* @param[in] reg Register address to read from.
|
||||
* @param[in] answer Byte to read.
|
||||
*
|
||||
* @return 1 on success.
|
||||
* @return -1 on error.
|
||||
*/
|
||||
int nrf24l01p_read_reg(nrf24l01p_t *dev, char reg, char *answer);
|
||||
|
||||
/**
|
||||
* @brief Write one register to the nrf24l01+ transceiver.
|
||||
*
|
||||
* @param[in] dev Transceiver device to use.
|
||||
* @param[in] reg Register address to write to.
|
||||
* @param[in] answer Byte to write.
|
||||
*
|
||||
* @return 1 on success.
|
||||
* @return -1 on error.
|
||||
*/
|
||||
int nrf24l01p_write_reg(nrf24l01p_t *dev, char reg, char write);
|
||||
|
||||
/**
|
||||
* @brief Initialize the nrf24l01+ transceiver.
|
||||
*
|
||||
* @ note
|
||||
* This function initializes the transceiver so that it is ready to use.
|
||||
*
|
||||
* @param[in] dev Transceiver device to use.
|
||||
* @param[in] spi SPI device to use.
|
||||
* @param[in] ce GPIO pin to use for chip enable.
|
||||
* @param[in] cs GPIO pin to use for chip select.
|
||||
* @param[in] irq GPIO pin to use for interrupt request.
|
||||
*
|
||||
* @return 1 on success.
|
||||
* @return -1 on error.
|
||||
*/
|
||||
int nrf24l01p_init(nrf24l01p_t *dev, spi_t spi, gpio_t ce, gpio_t csn, gpio_t irq);
|
||||
|
||||
/**
|
||||
* @brief Power on the nrf24l01+ transceiver.
|
||||
*
|
||||
* @param[in] dev Transceiver device to use.
|
||||
*
|
||||
* @return 1 on success.
|
||||
* @return -1 on error.
|
||||
*/
|
||||
int nrf24l01p_on(nrf24l01p_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Power off the nrf24l01+ transceiver.
|
||||
*
|
||||
* @param[in] dev Transceiver device to use.
|
||||
*
|
||||
* @return 1 on success.
|
||||
* @return -1 on error.
|
||||
*/
|
||||
int nrf24l01p_off(nrf24l01p_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Transmit payload laying in TX FIFO of the nrf24l01+ transceiver.
|
||||
*
|
||||
* @param[in] dev Transceiver device to use.
|
||||
*
|
||||
*/
|
||||
void nrf24l01p_transmit(nrf24l01p_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Read payload from RX FIFO of the nrf24l01+ transceiver.
|
||||
*
|
||||
* @param[in] dev Transceiver device to use.
|
||||
* @param[in] answer Buffer to receive bytes to.
|
||||
* @param[in] size Number of bytes to transfer. For nrf24l01+ in general 32.
|
||||
*
|
||||
* @return Number of bytes that were transfered.
|
||||
* @return -1 on error.
|
||||
*/
|
||||
int nrf24l01p_read_payload(nrf24l01p_t *dev, char *answer, unsigned int size);
|
||||
|
||||
/**
|
||||
* @brief Register a given ID to the nrf24l01+ transceiver.
|
||||
*
|
||||
* @param[in] dev Transceiver device to use.
|
||||
* @param[in] pid ID to register.
|
||||
*
|
||||
*/
|
||||
void nrf24l01p_register(nrf24l01p_t *dev, unsigned int *pid);
|
||||
|
||||
/**
|
||||
* @brief Unregister the nrf24l01+ transceiver from his ID.
|
||||
*
|
||||
* @param[in] dev Transceiver device to use.
|
||||
* @param[in] pid Actual ID to unregister.
|
||||
*
|
||||
* @return 0 on success.
|
||||
* @return -1 on error.
|
||||
*/
|
||||
int nrf24l01p_unregister(nrf24l01p_t *dev, unsigned int pid);
|
||||
|
||||
/**
|
||||
* @brief Get ID from the nrf24l01p transceiver.
|
||||
*
|
||||
* @param[in] dev Transceiver device to use.
|
||||
* @param[in] pid T.ransceiver ID
|
||||
*
|
||||
*/
|
||||
void nrf24l01p_get_id(nrf24l01p_t *dev, unsigned int *pid);
|
||||
|
||||
/**
|
||||
* @brief Start searching packets while in RX mode.
|
||||
*
|
||||
* @param[in] dev Transceiver device to use.
|
||||
*
|
||||
*/
|
||||
void nrf24l01p_start(nrf24l01p_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Stop searching packets while in RX mode.
|
||||
*
|
||||
* @param[in] dev Transceiver device to use.
|
||||
*
|
||||
*/
|
||||
void nrf24l01p_stop(nrf24l01p_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Preload TX FIFO with payload to transmit.
|
||||
*
|
||||
* @param[in] dev Transceiver device to use.
|
||||
* @param[in] data Buffer to preload.
|
||||
* @param[in] size Number of bytes in buffer. For nrf24l01+ e.g. 32
|
||||
*
|
||||
* @return 0 on success.
|
||||
* @return -1 on error.
|
||||
*/
|
||||
int nrf24l01p_preload(nrf24l01p_t *dev, char *data, unsigned int size);
|
||||
|
||||
/**
|
||||
* @brief Set the RF channel for the nrf24l01+ transceiver.
|
||||
*
|
||||
* @note
|
||||
* To ensure non-overlapping channels in 2Mbps mode, don't use directly
|
||||
* neighbouring channels in this mode.
|
||||
*
|
||||
* @param[in] dev Transceiver device to use.
|
||||
* @param[in] chan Buffer to preload.
|
||||
*
|
||||
* @return 1 on success.
|
||||
* @return -1 on error.
|
||||
*/
|
||||
int nrf24l01p_set_channel(nrf24l01p_t *dev, uint8_t chan);
|
||||
|
||||
/**
|
||||
* @brief Set the address width for the nrf24l01+ transceiver.
|
||||
*
|
||||
* @param[in] dev Transceiver device to use.
|
||||
* @param[in] aw Address width (type nrf24l01p_aw_t).
|
||||
*
|
||||
* @return 1 on success.
|
||||
* @return -1 on error.
|
||||
*/
|
||||
int nrf24l01p_set_address_width(nrf24l01p_t *dev, nrf24l01p_aw_t aw);
|
||||
|
||||
/**
|
||||
* @brief Set the RX payload width for the nrf24l01+ transceiver
|
||||
*
|
||||
* @ note
|
||||
* This function sets the payload width for one packet. If the maximum of 32 bytes is
|
||||
* exeeded, this value is set to 32.
|
||||
*
|
||||
* @param[in] dev Transceiver device to use.
|
||||
* @param[in] pipe RX pipe to set the payload width.
|
||||
* @param[in] width Numer of bytes per packet in RX payload.
|
||||
*
|
||||
* @return 1 on success.
|
||||
* @return -1 on error.
|
||||
*/
|
||||
int nrf24l01p_set_payload_width(nrf24l01p_t *dev, nrf24l01p_rx_pipe_t pipe, char width);
|
||||
|
||||
/**
|
||||
* @brief Set the TX address for the nrf24l01+ transceiver (byte array).
|
||||
*
|
||||
* @note
|
||||
* You can either use this function and give it a pointer to a byte array which
|
||||
* holds the address to set, or use "nrf24l01p_set_tx_address_long" which requires
|
||||
* a uint64_t which holds the address in the LSBs.
|
||||
*
|
||||
* @param[in] dev Transceiver device to use.
|
||||
* @param[in] saddr Byte array which holds the TX address.
|
||||
* @param[in] length Number of bytes in address array.
|
||||
*
|
||||
* @return 1 on success.
|
||||
* @return -1 on error.
|
||||
*/
|
||||
int nrf24l01p_set_tx_address(nrf24l01p_t *dev, char *saddr, unsigned int length);
|
||||
|
||||
/**
|
||||
* @brief Set the TX address for the nrf24l01+ transceiver (long int).
|
||||
*
|
||||
* @param[in] dev Transceiver device to use.
|
||||
* @param[in] saddr Long integer which holds the TX address in LSBs.
|
||||
* @param[in] length Number of relevant bytes in uint64_t.
|
||||
*
|
||||
* @return 1 on success.
|
||||
* @return -1 on error.
|
||||
*/
|
||||
int nrf24l01p_set_tx_address_long(nrf24l01p_t *dev, uint64_t saddr, unsigned int length);
|
||||
|
||||
/**
|
||||
* @brief Set the RX address for the nrf24l01+ transceiver (byte array).
|
||||
*
|
||||
* @note
|
||||
* You can either use this function and give it a pointer to a byte array which
|
||||
* holds the address to set, or use "nrf24l01p_set_rx_address_long" which requires
|
||||
* a uint64_t which holds the address in the LSBs.
|
||||
*
|
||||
* @param[in] dev Transceiver device to use.
|
||||
* @param[in] pipe RX pipe to set the address.
|
||||
* @param[in] saddr Byte array which holds the RX address.
|
||||
* @param[in] length Number of bytes in address array.
|
||||
*
|
||||
* @return 1 on success.
|
||||
* @return -1 on error.
|
||||
*/
|
||||
int nrf24l01p_set_rx_address(nrf24l01p_t *dev, nrf24l01p_rx_pipe_t pipe, char *saddr, unsigned int length);
|
||||
|
||||
/**
|
||||
* @brief Set the RX address for the nrf24l01+ transceiver (long int).
|
||||
*
|
||||
* @param[in] dev Transceiver device to use.
|
||||
* @param[in] pipe RX pipe to set the address.
|
||||
* @param[in] saddr Long integer which holds the RX address in LSBs.
|
||||
* @param[in] length Number of relevant bytes in uint64_t.
|
||||
*
|
||||
* @return 1 on success.
|
||||
* @return -1 on error.
|
||||
*/
|
||||
int nrf24l01p_set_rx_address_long(nrf24l01p_t *dev, nrf24l01p_rx_pipe_t pipe, uint64_t saddr, unsigned int length);
|
||||
|
||||
/**
|
||||
* @brief Get the TX address for the nrf24l01+ transceiver (long int).
|
||||
*
|
||||
* @param[in] dev Transceiver device to use.
|
||||
*
|
||||
* @return TX address of the nrf24l01+ transceiver.
|
||||
*/
|
||||
uint64_t nrf24l01p_get_tx_address_long(nrf24l01p_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Get the RX address for the nrf24l01+ transceiver (long int).
|
||||
*
|
||||
* @param[in] dev Transceiver device to use.
|
||||
* @param[in] pipe RX pipe to get the address from.
|
||||
*
|
||||
* @return RX address of the nrf24l01+ transceiver.
|
||||
*/
|
||||
uint64_t nrf24l01p_get_rx_address_long(nrf24l01p_t *dev, nrf24l01p_rx_pipe_t pipe);
|
||||
|
||||
/**
|
||||
* @brief Get the TX address for the nrf24l01+ transceiver (long int).
|
||||
*
|
||||
* @note
|
||||
* If you chose 2Mbps you should not allocate directly neighboring RF channels.
|
||||
*
|
||||
* @param[in] dev Transceiver device to use.
|
||||
* @param[in] dr Datarate (of type nrf24l01p_dr_t).
|
||||
*
|
||||
* @return 1 on success.
|
||||
* @return -1 on error.
|
||||
*/
|
||||
int nrf24l01p_set_datarate(nrf24l01p_t *dev, nrf24l01p_dr_t dr);
|
||||
|
||||
/**
|
||||
* @brief Get the status (register) of the nrf24l01+ transceiver device.
|
||||
*
|
||||
* @param[in] dev Transceiver device to use.s of the.
|
||||
*
|
||||
* @return Value of the status register.
|
||||
*/
|
||||
int nrf24l01p_get_status(nrf24l01p_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Set the transmit power for the nrf24l01+ transceiver device.
|
||||
*
|
||||
* @note
|
||||
* This function rounds the input values to the nearest possible setting.
|
||||
*
|
||||
* @param[in] dev Transceiver device to use.
|
||||
* @param[in] pwr TX power for the nrf24l01p transceiver.
|
||||
*
|
||||
* @return 1 on success.
|
||||
* @return -1 on error.
|
||||
*/
|
||||
int nrf24l01p_set_power(nrf24l01p_t *dev, int *pwr);
|
||||
|
||||
/**
|
||||
* @brief Get the transmit power for the nrf24l01+ transceiver device.
|
||||
*
|
||||
* @param[in] dev Transceiver device to use.
|
||||
*
|
||||
* @return TX power value of the nrf24l01+ transceiver.
|
||||
*/
|
||||
int nrf24l01p_get_power(nrf24l01p_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Set the nrf24l01+ into TX mode.
|
||||
*
|
||||
* @param[in] dev Transceiver device to use.
|
||||
*
|
||||
* @return 1 on success.
|
||||
* @return -1 on error.
|
||||
*/
|
||||
int nrf24l01p_set_txmode(nrf24l01p_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Set the nrf24l01+ into RX mode.
|
||||
*
|
||||
* @param[in] dev Transceiver device to use.
|
||||
*
|
||||
* @return 1 on success.
|
||||
* @return -1 on error.
|
||||
*/
|
||||
int nrf24l01p_set_rxmode(nrf24l01p_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Reset all interrupts on the nrf24l01+ transceiver.
|
||||
*
|
||||
* @param[in] dev Transceiver device to use.
|
||||
*
|
||||
* @return 1 on success.
|
||||
* @return -1 on error.
|
||||
*/
|
||||
int nrf24l01p_reset_all_interrupts(nrf24l01p_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Mask one interrupt on the nrf24l01+ transceiver.
|
||||
*
|
||||
* @note
|
||||
* There are three interrupts on the nrf24l01+ which can be masked:
|
||||
* "MASK_RX_DR", "MASK_TX_DS" and "MASK_MAX_RT". Theay are defined
|
||||
* in "include/nrf24l01p_settings.h".
|
||||
*
|
||||
* @param[in] dev Transceiver device to use.
|
||||
* @param[in] intr Transceiver device to use.
|
||||
*
|
||||
* @return 1 on success.
|
||||
* @return -1 on error.
|
||||
*/
|
||||
int nrf24l01p_mask_interrupt(nrf24l01p_t *dev, char intr);
|
||||
|
||||
/**
|
||||
* @brief Unmask one interrupt on the nrf24l01+ transceiver.
|
||||
*
|
||||
* @note
|
||||
* There are three interrupts on the nrf24l01+ which can be unmasked:
|
||||
* "MASK_RX_DR", "MASK_TX_DS" and "MASK_MAX_RT". Theay are defined
|
||||
* in "include/nrf24l01p_settings.h".
|
||||
*
|
||||
* @param[in] dev Transceiver device to use.
|
||||
* @param[in] intr Transceiver device to use.
|
||||
*
|
||||
* @return 1 on success.
|
||||
* @return -1 on error.
|
||||
*/
|
||||
int nrf24l01p_unmask_interrupt(nrf24l01p_t *dev, char intr);
|
||||
|
||||
/**
|
||||
* @brief Enable RX datapipe on the nrf24l01+ transceiver.
|
||||
*
|
||||
* @param[in] dev Transceiver device to use.
|
||||
* @param[in] pipe RX pipe to enable.
|
||||
*
|
||||
* @return 1 on success.
|
||||
* @return -1 on error.
|
||||
*/
|
||||
int nrf24l01p_enable_pipe(nrf24l01p_t *dev, nrf24l01p_rx_pipe_t pipe);
|
||||
|
||||
/**
|
||||
* @brief Disable RX datapipe on the nrf24l01+ transceiver.
|
||||
*
|
||||
* @param[in] dev Transceiver device to use.
|
||||
* @param[in] pipe RX pipe to disable.
|
||||
*
|
||||
* @return 1 on success.
|
||||
* @return -1 on error.
|
||||
*/
|
||||
int nrf24l01p_disable_pipe(nrf24l01p_t *dev, nrf24l01p_rx_pipe_t pipe);
|
||||
|
||||
/**
|
||||
* @brief Enable CRC error detection on the nrf24l01+ transceiver.
|
||||
*
|
||||
* @param[in] dev Transceiver device to use.
|
||||
* @param[in] crc Length of cyclic redundancy check (type nrf24l01p_crc_t).
|
||||
*
|
||||
* @return 1 on success.
|
||||
* @return -1 on error.
|
||||
*/
|
||||
int nrf24l01p_enable_crc(nrf24l01p_t *dev, nrf24l01p_crc_t crc);
|
||||
|
||||
/**
|
||||
* @brief Setup and enable automatic ACK and retransmission on the nrf24l01+ transceiver.
|
||||
*
|
||||
* @note
|
||||
* This function enables automatic acknowledgement for a given RX data pipe and also sets up the
|
||||
* mautomatic retransmission behavior.
|
||||
*
|
||||
* @param[in] dev Transceiver device to use.
|
||||
* @param[in] pipe RX pipe to setup auto ack.
|
||||
* @param[in] delay_retrans Automatic retransmission delay
|
||||
(type nrf24l01p_retransmit_delay_t)
|
||||
* @param[in] count_retrans Auto retransmit count.
|
||||
*
|
||||
* @return 1 on success.
|
||||
* @return -1 on error.
|
||||
*/
|
||||
int nrf24l01p_setup_auto_ack(nrf24l01p_t *dev, nrf24l01p_rx_pipe_t pipe, nrf24l01p_retransmit_delay_t delay_retrans, char count_retrans);
|
||||
|
||||
/**
|
||||
* @brief Disable automatic ACK on the nrf24l01+ transceiver.
|
||||
*
|
||||
* @param[in] dev Transceiver device to use.
|
||||
*
|
||||
* @return 1 on success.
|
||||
* @return -1 on error.
|
||||
*/
|
||||
int nrf24l01p_disable_all_auto_ack(nrf24l01p_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Flush TX FIFO on the nrf24l01+ transceiver.
|
||||
*
|
||||
* @param[in] dev Transceiver device to use.
|
||||
*
|
||||
* @return 1 on success.
|
||||
* @return -1 on error.
|
||||
*/
|
||||
int nrf24l01p_flush_tx_fifo(nrf24l01p_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Flush RX FIFO on the nrf24l01+ transceiver.
|
||||
*
|
||||
* @param[in] dev Transceiver device to use.
|
||||
*
|
||||
* @return 1 on success.
|
||||
* @return -1 on error.
|
||||
*/
|
||||
int nrf24l01p_flush_rx_fifo(nrf24l01p_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Callback that is called when interrupt occurs on interrupt
|
||||
* pin from the nrf24l01+ transceiver.
|
||||
*
|
||||
* @param[in] arg Used to pass transceiver device "dev".
|
||||
*/
|
||||
void nrf24l01p_rx_cb(void *arg);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __NRF24L01P_H */
|
||||
/** @} */
|
4
drivers/nrf24l01p/Makefile
Normal file
4
drivers/nrf24l01p/Makefile
Normal file
@ -0,0 +1,4 @@
|
||||
# Makefile for the NRF24L01+ radio driver
|
||||
MODULE = nrf24l01p
|
||||
|
||||
include $(RIOTBASE)/Makefile.base
|
129
drivers/nrf24l01p/include/nrf24l01p_settings.h
Normal file
129
drivers/nrf24l01p/include/nrf24l01p_settings.h
Normal file
@ -0,0 +1,129 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Hamburg University of Applied Sciences
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser General
|
||||
* Public License v2.1. See the file LICENSE in the top level directory for more
|
||||
* details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ingroup drivers_nrf24l01p
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief Low-level driver for nrf24l01+ transceiver
|
||||
*
|
||||
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
|
||||
* @author Peter Kietzmann <peter.kietzmann@haw-hamburg.de>
|
||||
*
|
||||
* @}
|
||||
*/
|
||||
|
||||
#ifndef __NRF24L01P_SETTINGS_H
|
||||
#define __NRF24L01P_SETTINGS_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define INITIAL_ADDRESS_WIDTH 5
|
||||
#define NRF24L01P_MAX_DATA_LENGTH 32
|
||||
#define INITIAL_RF_CHANNEL 5
|
||||
|
||||
#define DELAY_CS_TOGGLE_TICKS 2
|
||||
#define DELAY_AFTER_FUNC_TICKS 2
|
||||
#define DELAY_CE_HIGH_US HWTIMER_TICKS(20)
|
||||
#define DELAY_CHANGE_PWR_MODE_US HWTIMER_TICKS(1500)
|
||||
#define DELAY_CHANGE_TXRX_US HWTIMER_TICKS(130)
|
||||
#define DELAY_CE_START_US HWTIMER_TICKS(5)
|
||||
/*
|
||||
* This is the time which is needed to physically transmit the data.
|
||||
* Compare nrf24l01+ pruduct specification p.42. It is computed just
|
||||
* for this setup
|
||||
*/
|
||||
#define DELAY_DATA_ON_AIR HWTIMER_TICKS(1300)
|
||||
|
||||
|
||||
#define CMD_R_REGISTER 0x00
|
||||
#define CMD_W_REGISTER 0x20
|
||||
#define CMD_R_RX_PAYLOAD 0x61
|
||||
#define CMD_W_TX_PAYLOAD 0xa0
|
||||
#define CMD_FLUSH_TX 0xe1
|
||||
#define CMD_FLUSH_RX 0xe2
|
||||
#define CMD_REUSE_TX_PL 0xe3
|
||||
#define CMD_R_RX_PL_WID 0x60
|
||||
#define CMD_W_ACK_PAYLOAD 0xa8
|
||||
#define CMD_W_TX_PAYLOAD_NOACK 0xb0
|
||||
#define CMD_NOP 0xff
|
||||
|
||||
#define REGISTER_MASK 0x1F
|
||||
|
||||
|
||||
#define REG_CONFIG 0x00 /* config */
|
||||
#define REG_EN_AA 0x01 /* enhanced shockburst */
|
||||
#define REG_EN_RXADDR 0x02
|
||||
#define REG_SETUP_AW 0x03
|
||||
#define REG_SETUP_RETR 0x04
|
||||
#define REG_RF_CH 0x05
|
||||
#define REG_RF_SETUP 0x06
|
||||
#define REG_STATUS 0x07
|
||||
#define REG_OBSERVE_TX 0x08
|
||||
#define REG_RPD 0x09
|
||||
#define REG_RX_ADDR_P0 0x0a
|
||||
#define REG_RX_ADDR_P1 0x0b
|
||||
#define REG_RX_ADDR_P2 0x0c
|
||||
#define REG_RX_ADDR_P3 0x0d
|
||||
#define REG_RX_ADDR_P4 0x0e
|
||||
#define REG_RX_ADDR_P5 0x0f
|
||||
#define REG_TX_ADDR 0x10
|
||||
#define REG_RX_PW_P0 0x11
|
||||
#define REG_RX_PW_P1 0x12
|
||||
#define REG_RX_PW_P2 0x13
|
||||
#define REG_RX_PW_P3 0x14
|
||||
#define REG_RX_PW_P4 0x15
|
||||
#define REG_RX_PW_P5 0x16
|
||||
#define REG_FIFO_STATUS 0x17
|
||||
#define REG_DYNPD 0x1c
|
||||
#define REG_FEATURE 0x1d
|
||||
|
||||
/* Bits in CONFIG register */
|
||||
#define MASK_RX_DR 0x40
|
||||
#define MASK_TX_DS 0x20
|
||||
#define MASK_MAX_RT 0x10
|
||||
#define EN_CRC 0x08
|
||||
#define CRCO 0x04
|
||||
#define PWR_UP 0x02
|
||||
#define PRIM_RX 0x01
|
||||
|
||||
/* Bits in STATUS register */
|
||||
#define RX_DR 0x40
|
||||
#define TX_DS 0x20
|
||||
#define MAX_RT 0x10
|
||||
#define RX_P_NO 0x0e
|
||||
#define TX_FULL 0x01
|
||||
#define ALL_INT_MASK 0x70
|
||||
|
||||
#define RF_SETUP_CONT_WAVE (1 << 7)
|
||||
#define RF_SETUP_RF_DR_LOW (1 << 5)
|
||||
#define RF_SETUP_PLL_LOCK (1 << 4)
|
||||
#define RF_SETUP_RF_DR_HIGH (1 << 3)
|
||||
#define RF_SETUP_RF_PWR (3 << 1)
|
||||
|
||||
#define RF_CH_MASK 0x7f
|
||||
|
||||
#define DYNPD_DPL_P5 (1 << 5)
|
||||
#define DYNPD_DPL_P4 (1 << 4)
|
||||
#define DYNPD_DPL_P3 (1 << 3)
|
||||
#define DYNPD_DPL_P2 (1 << 2)
|
||||
#define DYNPD_DPL_P1 (1 << 1)
|
||||
#define DYNPD_DPL_P0 (1 << 0)
|
||||
|
||||
#define FEATURE_EN_DPL (1 << 2)
|
||||
#define FEATURE_EN_ACK_PAY (1 << 1)
|
||||
#define FEATURE_EN_DYN_ACK (1 << 0)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __NRF24L01P_SETTINGS_H */
|
883
drivers/nrf24l01p/nrf24l01p.c
Normal file
883
drivers/nrf24l01p/nrf24l01p.c
Normal file
@ -0,0 +1,883 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Hamburg University of Applied Sciences
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser General
|
||||
* Public License v2.1. See the file LICENSE in the top level directory for more
|
||||
* details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ingroup drivers_nrf24l01p
|
||||
* @{
|
||||
* @author Peter Kietzmann <peter.kietzmann@haw-hamburg.de>
|
||||
* @}
|
||||
*/
|
||||
#include "nrf24l01p.h"
|
||||
#include "nrf24l01p_settings.h"
|
||||
#include "periph/gpio.h"
|
||||
#include "periph/spi.h"
|
||||
#include "hwtimer.h"
|
||||
#include "thread.h"
|
||||
#include "msg.h"
|
||||
|
||||
|
||||
#define ENABLE_DEBUG (1)
|
||||
#include "debug.h"
|
||||
|
||||
|
||||
int nrf24l01p_read_reg(nrf24l01p_t *dev, char reg, char *answer)
|
||||
{
|
||||
int status;
|
||||
|
||||
gpio_clear(dev->cs);
|
||||
hwtimer_spin(DELAY_CS_TOGGLE_TICKS);
|
||||
status = spi_transfer_reg(dev->spi, (CMD_R_REGISTER | (REGISTER_MASK & reg)), CMD_NOP, answer);
|
||||
hwtimer_spin(DELAY_CS_TOGGLE_TICKS);
|
||||
gpio_set(dev->cs);
|
||||
|
||||
hwtimer_spin(DELAY_AFTER_FUNC_TICKS);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
int nrf24l01p_write_reg(nrf24l01p_t *dev, char reg, char write)
|
||||
{
|
||||
int status;
|
||||
char reg_content;
|
||||
|
||||
gpio_clear(dev->cs);
|
||||
hwtimer_spin(DELAY_CS_TOGGLE_TICKS);
|
||||
status = spi_transfer_reg(dev->spi, (CMD_W_REGISTER | (REGISTER_MASK & reg)), write, ®_content);
|
||||
hwtimer_spin(DELAY_CS_TOGGLE_TICKS);
|
||||
gpio_set(dev->cs);
|
||||
|
||||
hwtimer_spin(DELAY_AFTER_FUNC_TICKS);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
int nrf24l01p_init(nrf24l01p_t *dev, spi_t spi, gpio_t ce, gpio_t cs, gpio_t irq)
|
||||
{
|
||||
int status;
|
||||
char INITIAL_TX_ADDRESS[] = {0xe7, 0xe7, 0xe7, 0xe7, 0xe7,};
|
||||
char INITIAL_RX_ADDRESS[] = {0xe7, 0xe7, 0xe7, 0xe7, 0xe7,};
|
||||
|
||||
dev->spi = spi;
|
||||
dev->ce = ce;
|
||||
dev->cs = cs;
|
||||
dev->irq = irq;
|
||||
dev->listener = KERNEL_PID_UNDEF;
|
||||
|
||||
/* Init CE pin */
|
||||
gpio_init_out(dev->ce, GPIO_NOPULL);
|
||||
|
||||
/* Init CS pin */
|
||||
gpio_init_out(dev->cs, GPIO_NOPULL);
|
||||
gpio_set(dev->cs);
|
||||
|
||||
/* Init IRQ pin */
|
||||
gpio_init_int(dev->irq, GPIO_PULLUP, GPIO_FALLING, nrf24l01p_rx_cb, dev);
|
||||
|
||||
|
||||
/* Init SPI */
|
||||
spi_poweron(dev->spi);
|
||||
status = spi_init_master(dev->spi, SPI_CONF_FIRST_RISING, SPI_SPEED_400KHZ);
|
||||
|
||||
if (status < 0) {
|
||||
return status;
|
||||
}
|
||||
|
||||
hwtimer_spin(DELAY_AFTER_FUNC_TICKS);
|
||||
|
||||
/* Flush TX FIFIO */
|
||||
status = nrf24l01p_flush_tx_fifo(dev);
|
||||
|
||||
if (status < 0) {
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Flush RX FIFIO */
|
||||
status = nrf24l01p_flush_tx_fifo(dev);
|
||||
|
||||
if (status < 0) {
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Setup adress width */
|
||||
status = nrf24l01p_set_address_width(dev, NRF24L01P_AW_5BYTE);
|
||||
|
||||
if (status < 0) {
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Setup payload width */
|
||||
status = nrf24l01p_set_payload_width(dev, NRF24L01P_PIPE0, NRF24L01P_MAX_DATA_LENGTH);
|
||||
|
||||
if (status < 0) {
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Set RF channel */
|
||||
status = nrf24l01p_set_channel(dev, INITIAL_RF_CHANNEL);
|
||||
|
||||
if (status < 0) {
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Set RF power */
|
||||
status = nrf24l01p_set_power(dev, 0);
|
||||
|
||||
if (status < 0) {
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Set RF datarate */
|
||||
status = nrf24l01p_set_datarate(dev, NRF24L01P_DR_250KBS);
|
||||
|
||||
if (status < 0) {
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Set TX Address */
|
||||
status = nrf24l01p_set_tx_address(dev, INITIAL_TX_ADDRESS, INITIAL_ADDRESS_WIDTH);
|
||||
|
||||
if (status < 0) {
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Set RX Adress */
|
||||
status = nrf24l01p_set_rx_address(dev, NRF24L01P_PIPE0, INITIAL_RX_ADDRESS, INITIAL_ADDRESS_WIDTH);
|
||||
|
||||
if (status < 0) {
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Reset auto ack for all pipes */
|
||||
status = nrf24l01p_disable_all_auto_ack(dev);
|
||||
|
||||
if (status < 0) {
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Setup Auto ACK and retransmission */
|
||||
status = nrf24l01p_setup_auto_ack(dev, NRF24L01P_PIPE0, NRF24L01P_RETR_750US, 15);
|
||||
|
||||
if (status < 0) {
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Setup CRC */
|
||||
status = nrf24l01p_enable_crc(dev, NRF24L01P_CRC_2BYTE);
|
||||
|
||||
if (status < 0) {
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Reset all interrupt flags */
|
||||
status = nrf24l01p_reset_all_interrupts(dev);
|
||||
|
||||
if (status < 0) {
|
||||
return status;
|
||||
}
|
||||
|
||||
return nrf24l01p_on(dev);
|
||||
}
|
||||
|
||||
int nrf24l01p_on(nrf24l01p_t *dev)
|
||||
{
|
||||
char read;
|
||||
int status;
|
||||
|
||||
gpio_clear(dev->cs);
|
||||
nrf24l01p_read_reg(dev, REG_CONFIG, &read);
|
||||
hwtimer_spin(DELAY_CS_TOGGLE_TICKS);
|
||||
status = nrf24l01p_write_reg(dev, REG_CONFIG, (read | PWR_UP));
|
||||
hwtimer_spin(DELAY_CS_TOGGLE_TICKS);
|
||||
gpio_set(dev->cs);
|
||||
|
||||
hwtimer_wait(DELAY_CHANGE_PWR_MODE_US);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
int nrf24l01p_off(nrf24l01p_t *dev)
|
||||
{
|
||||
char read;
|
||||
int status;
|
||||
|
||||
gpio_clear(dev->cs);
|
||||
nrf24l01p_read_reg(dev, REG_CONFIG, &read);
|
||||
hwtimer_spin(DELAY_CS_TOGGLE_TICKS);
|
||||
status = nrf24l01p_write_reg(dev, REG_CONFIG, (read & ~PWR_UP));
|
||||
hwtimer_spin(DELAY_CS_TOGGLE_TICKS);
|
||||
gpio_set(dev->cs);
|
||||
|
||||
hwtimer_wait(DELAY_CHANGE_PWR_MODE_US);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
void nrf24l01p_transmit(nrf24l01p_t *dev)
|
||||
{
|
||||
gpio_set(dev->ce);
|
||||
hwtimer_wait(DELAY_CE_HIGH_US); /* at least 10 us high */
|
||||
gpio_clear(dev->ce);
|
||||
|
||||
hwtimer_spin(DELAY_CHANGE_TXRX_US);
|
||||
}
|
||||
|
||||
int nrf24l01p_read_payload(nrf24l01p_t *dev, char *answer, unsigned int size)
|
||||
{
|
||||
int status;
|
||||
|
||||
gpio_clear(dev->cs);
|
||||
hwtimer_spin(DELAY_CS_TOGGLE_TICKS);
|
||||
status = spi_transfer_regs(dev->spi, CMD_R_RX_PAYLOAD, 0, answer, size);
|
||||
hwtimer_spin(DELAY_CS_TOGGLE_TICKS);
|
||||
gpio_set(dev->cs);
|
||||
hwtimer_spin(DELAY_AFTER_FUNC_TICKS);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
void nrf24l01p_register(nrf24l01p_t *dev, unsigned int *pid)
|
||||
{
|
||||
dev->listener = *pid;
|
||||
}
|
||||
|
||||
int nrf24l01p_unregister(nrf24l01p_t *dev, unsigned int pid)
|
||||
{
|
||||
if (dev != NULL && dev->listener == pid) {
|
||||
dev->listener = 0;
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
void nrf24l01p_get_id(nrf24l01p_t *dev, unsigned int *pid)
|
||||
{
|
||||
*((int *)pid) = dev->listener;
|
||||
}
|
||||
|
||||
void nrf24l01p_start(nrf24l01p_t *dev)
|
||||
{
|
||||
gpio_set(dev->ce);
|
||||
hwtimer_wait(DELAY_CE_START_US);
|
||||
}
|
||||
|
||||
void nrf24l01p_stop(nrf24l01p_t *dev)
|
||||
{
|
||||
hwtimer_spin(DELAY_CS_TOGGLE_TICKS);
|
||||
gpio_clear(dev->ce);
|
||||
}
|
||||
|
||||
int nrf24l01p_preload(nrf24l01p_t *dev, char *data, unsigned int size)
|
||||
{
|
||||
int status;
|
||||
|
||||
size = (size <= 32) ? size : 32;
|
||||
|
||||
gpio_clear(dev->cs);
|
||||
hwtimer_spin(DELAY_CS_TOGGLE_TICKS);
|
||||
status = spi_transfer_regs(dev->spi, CMD_W_TX_PAYLOAD, data, NULL, size);
|
||||
hwtimer_spin(DELAY_CS_TOGGLE_TICKS);
|
||||
gpio_set(dev->cs);
|
||||
|
||||
hwtimer_spin(DELAY_AFTER_FUNC_TICKS);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
int nrf24l01p_set_channel(nrf24l01p_t *dev, uint8_t chan)
|
||||
{
|
||||
if (chan > 125) {
|
||||
chan = 125;
|
||||
}
|
||||
|
||||
return nrf24l01p_write_reg(dev, REG_RF_CH, chan);
|
||||
}
|
||||
|
||||
int nrf24l01p_set_address_width(nrf24l01p_t *dev, nrf24l01p_aw_t aw)
|
||||
{
|
||||
char aw_setup;
|
||||
nrf24l01p_read_reg(dev, REG_SETUP_AW, &aw_setup);
|
||||
|
||||
hwtimer_spin(DELAY_AFTER_FUNC_TICKS);
|
||||
|
||||
switch (aw) {
|
||||
case NRF24L01P_AW_3BYTE:
|
||||
aw_setup &= ~(3);
|
||||
aw_setup |= 1;
|
||||
break;
|
||||
|
||||
case NRF24L01P_AW_4BYTE:
|
||||
aw_setup &= ~(3);
|
||||
aw_setup |= 2;
|
||||
break;
|
||||
|
||||
case NRF24L01P_AW_5BYTE:
|
||||
aw_setup &= ~(3);
|
||||
aw_setup |= 3;
|
||||
break;
|
||||
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
return nrf24l01p_write_reg(dev, REG_SETUP_AW, aw_setup);
|
||||
}
|
||||
|
||||
int nrf24l01p_set_payload_width(nrf24l01p_t *dev, nrf24l01p_rx_pipe_t pipe, char width)
|
||||
{
|
||||
char pipe_pw_address;
|
||||
|
||||
switch (pipe) {
|
||||
case NRF24L01P_PIPE0:
|
||||
pipe_pw_address = REG_RX_PW_P0;
|
||||
break;
|
||||
|
||||
case NRF24L01P_PIPE1:
|
||||
pipe_pw_address = REG_RX_PW_P1;
|
||||
break;
|
||||
|
||||
case NRF24L01P_PIPE2:
|
||||
pipe_pw_address = REG_RX_PW_P2;
|
||||
break;
|
||||
|
||||
case NRF24L01P_PIPE3:
|
||||
pipe_pw_address = REG_RX_PW_P3;
|
||||
break;
|
||||
|
||||
case NRF24L01P_PIPE4:
|
||||
pipe_pw_address = REG_RX_PW_P4;
|
||||
break;
|
||||
|
||||
case NRF24L01P_PIPE5:
|
||||
pipe_pw_address = REG_RX_PW_P5;
|
||||
break;
|
||||
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (width < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (width > 32) {
|
||||
width = 32;
|
||||
}
|
||||
|
||||
return nrf24l01p_write_reg(dev, pipe_pw_address, width);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int nrf24l01p_set_tx_address(nrf24l01p_t *dev, char *saddr, unsigned int length)
|
||||
{
|
||||
int status;
|
||||
|
||||
gpio_clear(dev->cs);
|
||||
hwtimer_spin(DELAY_CS_TOGGLE_TICKS);
|
||||
status = spi_transfer_regs(dev->spi, (CMD_W_REGISTER | (REGISTER_MASK & REG_TX_ADDR)), saddr, NULL, length); /* address width is 5 byte */
|
||||
hwtimer_spin(DELAY_CS_TOGGLE_TICKS);
|
||||
gpio_set(dev->cs);
|
||||
|
||||
hwtimer_spin(DELAY_AFTER_FUNC_TICKS);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
int nrf24l01p_set_tx_address_long(nrf24l01p_t *dev, uint64_t saddr, unsigned int length)
|
||||
{
|
||||
int status;
|
||||
|
||||
char buf[length];
|
||||
|
||||
if (length <= INITIAL_ADDRESS_WIDTH) {
|
||||
for (int i = 0; i < length; i++) {
|
||||
|
||||
buf[i] = (uint8_t)(saddr >> (((length - 1) - i) * sizeof(uint64_t)));
|
||||
}
|
||||
}
|
||||
else {
|
||||
return -1;
|
||||
}
|
||||
|
||||
gpio_clear(dev->cs);
|
||||
hwtimer_spin(DELAY_CS_TOGGLE_TICKS);
|
||||
status = spi_transfer_regs(dev->spi, (CMD_W_REGISTER | (REGISTER_MASK & REG_TX_ADDR)), buf, NULL, length); /* address width is 5 byte */
|
||||
hwtimer_spin(DELAY_CS_TOGGLE_TICKS);
|
||||
gpio_set(dev->cs);
|
||||
|
||||
hwtimer_spin(DELAY_AFTER_FUNC_TICKS);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
uint64_t nrf24l01p_get_tx_address_long(nrf24l01p_t *dev)
|
||||
{
|
||||
int status;
|
||||
uint64_t saddr_64 = 0;
|
||||
char addr_array[INITIAL_ADDRESS_WIDTH];
|
||||
|
||||
gpio_clear(dev->cs);
|
||||
hwtimer_spin(DELAY_CS_TOGGLE_TICKS);
|
||||
status = spi_transfer_regs(dev->spi, (CMD_R_REGISTER | (REGISTER_MASK & REG_TX_ADDR)), 0, addr_array, INITIAL_ADDRESS_WIDTH); /* address width is 5 byte */
|
||||
hwtimer_spin(DELAY_CS_TOGGLE_TICKS);
|
||||
gpio_set(dev->cs);
|
||||
|
||||
hwtimer_spin(DELAY_AFTER_FUNC_TICKS);
|
||||
|
||||
if (status < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
hwtimer_spin(DELAY_AFTER_FUNC_TICKS);
|
||||
|
||||
for (int i = 0; i < INITIAL_ADDRESS_WIDTH; i++) {
|
||||
saddr_64 |= (((uint64_t) addr_array[i]) << (8 * (INITIAL_ADDRESS_WIDTH - i - 1)));
|
||||
}
|
||||
|
||||
return saddr_64;
|
||||
}
|
||||
|
||||
|
||||
int nrf24l01p_set_rx_address(nrf24l01p_t *dev, nrf24l01p_rx_pipe_t pipe, char *saddr, unsigned int length)
|
||||
{
|
||||
int status;
|
||||
char pipe_addr;
|
||||
|
||||
switch (pipe) {
|
||||
case NRF24L01P_PIPE0:
|
||||
pipe_addr = REG_RX_ADDR_P0;
|
||||
break;
|
||||
|
||||
case NRF24L01P_PIPE1:
|
||||
pipe_addr = REG_RX_ADDR_P1;
|
||||
break;
|
||||
|
||||
case NRF24L01P_PIPE2:
|
||||
pipe_addr = REG_RX_ADDR_P2;
|
||||
break;
|
||||
|
||||
case NRF24L01P_PIPE3:
|
||||
pipe_addr = REG_RX_ADDR_P3;
|
||||
break;
|
||||
|
||||
case NRF24L01P_PIPE4:
|
||||
pipe_addr = REG_RX_ADDR_P4;
|
||||
break;
|
||||
|
||||
case NRF24L01P_PIPE5:
|
||||
pipe_addr = REG_RX_ADDR_P5;
|
||||
break;
|
||||
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
gpio_clear(dev->cs);
|
||||
hwtimer_spin(DELAY_CS_TOGGLE_TICKS);
|
||||
status = spi_transfer_regs(dev->spi, (CMD_W_REGISTER | (REGISTER_MASK & pipe_addr)), saddr, NULL, length); /* address width is 5 byte */
|
||||
hwtimer_spin(DELAY_CS_TOGGLE_TICKS);
|
||||
gpio_set(dev->cs);
|
||||
|
||||
hwtimer_spin(DELAY_AFTER_FUNC_TICKS);
|
||||
|
||||
/* Enable this pipe */
|
||||
nrf24l01p_enable_pipe(dev, pipe);
|
||||
return status;
|
||||
}
|
||||
|
||||
int nrf24l01p_set_rx_address_long(nrf24l01p_t *dev, nrf24l01p_rx_pipe_t pipe, uint64_t saddr, unsigned int length)
|
||||
{
|
||||
char buf[length];
|
||||
|
||||
if (length <= INITIAL_ADDRESS_WIDTH) {
|
||||
for (int i = 0; i < length; i++) {
|
||||
|
||||
buf[i] = (uint8_t)(saddr >> (((length - 1) - i) * 8));
|
||||
}
|
||||
}
|
||||
else {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return nrf24l01p_set_rx_address(dev, pipe, buf, length);
|
||||
}
|
||||
|
||||
|
||||
uint64_t nrf24l01p_get_rx_address_long(nrf24l01p_t *dev, nrf24l01p_rx_pipe_t pipe)
|
||||
{
|
||||
int status;
|
||||
char pipe_addr;
|
||||
uint64_t saddr_64 = 0;
|
||||
|
||||
char addr_array[INITIAL_ADDRESS_WIDTH];
|
||||
|
||||
switch (pipe) {
|
||||
case NRF24L01P_PIPE0:
|
||||
pipe_addr = REG_RX_ADDR_P0;
|
||||
break;
|
||||
|
||||
case NRF24L01P_PIPE1:
|
||||
pipe_addr = REG_RX_ADDR_P1;
|
||||
break;
|
||||
|
||||
case NRF24L01P_PIPE2:
|
||||
pipe_addr = REG_RX_ADDR_P2;
|
||||
break;
|
||||
|
||||
case NRF24L01P_PIPE3:
|
||||
pipe_addr = REG_RX_ADDR_P3;
|
||||
break;
|
||||
|
||||
case NRF24L01P_PIPE4:
|
||||
pipe_addr = REG_RX_ADDR_P4;
|
||||
break;
|
||||
|
||||
case NRF24L01P_PIPE5:
|
||||
pipe_addr = REG_RX_ADDR_P5;
|
||||
break;
|
||||
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
gpio_clear(dev->cs);
|
||||
hwtimer_spin(DELAY_CS_TOGGLE_TICKS);
|
||||
status = spi_transfer_regs(dev->spi, (CMD_R_REGISTER | (REGISTER_MASK & pipe_addr)), 0, addr_array, INITIAL_ADDRESS_WIDTH); /* address width is 5 byte */
|
||||
hwtimer_spin(DELAY_CS_TOGGLE_TICKS);
|
||||
gpio_set(dev->cs);
|
||||
|
||||
if (status < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
hwtimer_spin(DELAY_AFTER_FUNC_TICKS);
|
||||
|
||||
for (int i = 0; i < INITIAL_ADDRESS_WIDTH; i++) {
|
||||
saddr_64 |= (((uint64_t) addr_array[i]) << (8 * (INITIAL_ADDRESS_WIDTH - i - 1)));
|
||||
}
|
||||
|
||||
return saddr_64;
|
||||
}
|
||||
|
||||
|
||||
int nrf24l01p_set_datarate(nrf24l01p_t *dev, nrf24l01p_dr_t dr)
|
||||
{
|
||||
char rf_setup;
|
||||
|
||||
nrf24l01p_read_reg(dev, REG_RF_SETUP, &rf_setup);
|
||||
|
||||
switch (dr) {
|
||||
case NRF24L01P_DR_250KBS:
|
||||
rf_setup |= RF_SETUP_RF_DR_LOW;
|
||||
rf_setup &= ~(RF_SETUP_RF_DR_HIGH);
|
||||
break;
|
||||
|
||||
case NRF24L01P_DR_1MBS:
|
||||
rf_setup &= ~(RF_SETUP_RF_DR_LOW | RF_SETUP_RF_DR_HIGH);
|
||||
break;
|
||||
|
||||
case NRF24L01P_DR_2MBS:
|
||||
rf_setup &= ~RF_SETUP_RF_DR_LOW;
|
||||
rf_setup |= RF_SETUP_RF_DR_HIGH;
|
||||
break;
|
||||
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
return nrf24l01p_write_reg(dev, REG_RF_SETUP, rf_setup);
|
||||
}
|
||||
|
||||
int nrf24l01p_get_status(nrf24l01p_t *dev)
|
||||
{
|
||||
char status;
|
||||
gpio_clear(dev->cs);
|
||||
hwtimer_spin(DELAY_CS_TOGGLE_TICKS);
|
||||
spi_transfer_byte(dev->spi, CMD_NOP, &status);
|
||||
hwtimer_spin(DELAY_CS_TOGGLE_TICKS);
|
||||
gpio_set(dev->cs);
|
||||
|
||||
hwtimer_spin(DELAY_AFTER_FUNC_TICKS);
|
||||
|
||||
return (int)status;
|
||||
}
|
||||
|
||||
int nrf24l01p_set_power(nrf24l01p_t *dev, int *pwr)
|
||||
{
|
||||
char rf_setup;
|
||||
|
||||
nrf24l01p_read_reg(dev, REG_RF_SETUP, &rf_setup);
|
||||
|
||||
if (*pwr >= -3) {
|
||||
rf_setup &= ~(3 << 1);
|
||||
rf_setup |= (NRF24L01P_PWR_0DBM << 1);
|
||||
}
|
||||
|
||||
if (*pwr < -3) {
|
||||
rf_setup &= ~(3 << 1);
|
||||
rf_setup |= (NRF24L01P_PWR_N6DBM << 1);
|
||||
}
|
||||
|
||||
if (*pwr < -9) {
|
||||
rf_setup &= ~(3 << 1);
|
||||
rf_setup |= (NRF24L01P_PWR_N12DBM << 1);
|
||||
}
|
||||
|
||||
if (*pwr < -15) {
|
||||
rf_setup &= ~(3 << 1);
|
||||
}
|
||||
|
||||
return nrf24l01p_write_reg(dev, REG_RF_SETUP, rf_setup);
|
||||
}
|
||||
|
||||
int nrf24l01p_get_power(nrf24l01p_t *dev)
|
||||
{
|
||||
char rf_setup;
|
||||
int pwr;
|
||||
|
||||
nrf24l01p_read_reg(dev, REG_RF_SETUP, &rf_setup);
|
||||
|
||||
if ((rf_setup & 0x6) == 0) {
|
||||
pwr = -18;
|
||||
}
|
||||
|
||||
if ((rf_setup & 0x6) == 2) {
|
||||
pwr = -12;
|
||||
}
|
||||
|
||||
if ((rf_setup & 0x6) == 4) {
|
||||
pwr = -6;
|
||||
}
|
||||
|
||||
if ((rf_setup & 0x6) == 6) {
|
||||
pwr = 0;
|
||||
}
|
||||
|
||||
return pwr;
|
||||
}
|
||||
|
||||
|
||||
int nrf24l01p_set_txmode(nrf24l01p_t *dev)
|
||||
{
|
||||
char conf;
|
||||
int status;
|
||||
|
||||
nrf24l01p_stop(dev);
|
||||
|
||||
nrf24l01p_mask_interrupt(dev, (MASK_RX_DR | MASK_TX_DS | MASK_MAX_RT));
|
||||
|
||||
nrf24l01p_flush_tx_fifo(dev);
|
||||
|
||||
nrf24l01p_read_reg(dev, REG_CONFIG, &conf);
|
||||
conf &= ~(PRIM_RX);
|
||||
status = nrf24l01p_write_reg(dev, REG_CONFIG, conf);
|
||||
|
||||
hwtimer_wait(DELAY_CHANGE_TXRX_US);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
int nrf24l01p_set_rxmode(nrf24l01p_t *dev)
|
||||
{
|
||||
char conf;
|
||||
int status;
|
||||
|
||||
nrf24l01p_unmask_interrupt(dev, MASK_RX_DR);
|
||||
nrf24l01p_mask_interrupt(dev, (MASK_TX_DS | MASK_MAX_RT));
|
||||
|
||||
nrf24l01p_flush_rx_fifo(dev);
|
||||
|
||||
nrf24l01p_read_reg(dev, REG_CONFIG, &conf);
|
||||
conf |= PRIM_RX;
|
||||
status = nrf24l01p_write_reg(dev, REG_CONFIG, conf);
|
||||
|
||||
nrf24l01p_start(dev);
|
||||
|
||||
hwtimer_wait(DELAY_CHANGE_TXRX_US);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
int nrf24l01p_reset_all_interrupts(nrf24l01p_t *dev)
|
||||
{
|
||||
return nrf24l01p_write_reg(dev, REG_STATUS, ALL_INT_MASK);
|
||||
}
|
||||
|
||||
int nrf24l01p_mask_interrupt(nrf24l01p_t *dev, char intr)
|
||||
{
|
||||
char conf;
|
||||
|
||||
nrf24l01p_read_reg(dev, REG_CONFIG, &conf);
|
||||
conf |= intr;
|
||||
|
||||
return nrf24l01p_write_reg(dev, REG_CONFIG, conf);
|
||||
}
|
||||
|
||||
int nrf24l01p_unmask_interrupt(nrf24l01p_t *dev, char intr)
|
||||
{
|
||||
char conf;
|
||||
|
||||
nrf24l01p_read_reg(dev, REG_CONFIG, &conf);
|
||||
conf &= ~intr;
|
||||
|
||||
return nrf24l01p_write_reg(dev, REG_CONFIG, conf);
|
||||
}
|
||||
|
||||
int nrf24l01p_enable_pipe(nrf24l01p_t *dev, nrf24l01p_rx_pipe_t pipe)
|
||||
{
|
||||
char pipe_conf;
|
||||
|
||||
nrf24l01p_read_reg(dev, REG_EN_RXADDR, &pipe_conf);
|
||||
pipe_conf |= (1 << pipe);
|
||||
|
||||
return nrf24l01p_write_reg(dev, REG_EN_RXADDR, pipe_conf);
|
||||
}
|
||||
|
||||
int nrf24l01p_disable_pipe(nrf24l01p_t *dev, nrf24l01p_rx_pipe_t pipe)
|
||||
{
|
||||
char pipe_conf;
|
||||
|
||||
nrf24l01p_read_reg(dev, REG_EN_RXADDR, &pipe_conf);
|
||||
pipe_conf &= ~(1 << pipe);
|
||||
|
||||
return nrf24l01p_write_reg(dev, REG_EN_RXADDR, pipe_conf);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int nrf24l01p_enable_crc(nrf24l01p_t *dev, nrf24l01p_crc_t crc)
|
||||
{
|
||||
char conf;
|
||||
|
||||
nrf24l01p_read_reg(dev, REG_CONFIG, &conf);
|
||||
|
||||
switch (crc) {
|
||||
case NRF24L01P_CRC_1BYTE:
|
||||
conf &= ~(CRCO);
|
||||
break;
|
||||
|
||||
case NRF24L01P_CRC_2BYTE:
|
||||
conf |= CRCO;
|
||||
break;
|
||||
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
return nrf24l01p_write_reg(dev, REG_CONFIG, (conf | EN_CRC));
|
||||
}
|
||||
|
||||
int nrf24l01p_setup_auto_ack(nrf24l01p_t *dev, nrf24l01p_rx_pipe_t pipe, nrf24l01p_retransmit_delay_t delay_retrans, char count_retrans)
|
||||
{
|
||||
char en_aa;
|
||||
int status;
|
||||
nrf24l01p_read_reg(dev, REG_EN_AA, &en_aa);
|
||||
|
||||
switch (pipe) {
|
||||
case NRF24L01P_PIPE0:
|
||||
en_aa |= (1 << 0);
|
||||
break;
|
||||
|
||||
case NRF24L01P_PIPE1:
|
||||
en_aa |= (1 << 1);
|
||||
break;
|
||||
|
||||
case NRF24L01P_PIPE2:
|
||||
en_aa |= (1 << 2);
|
||||
break;
|
||||
|
||||
case NRF24L01P_PIPE3:
|
||||
en_aa |= (1 << 3);
|
||||
break;
|
||||
|
||||
case NRF24L01P_PIPE4:
|
||||
en_aa |= (1 << 4);
|
||||
break;
|
||||
|
||||
case NRF24L01P_PIPE5:
|
||||
en_aa |= (1 << 5);
|
||||
break;
|
||||
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Enable Auto Ack */
|
||||
status = nrf24l01p_write_reg(dev, REG_EN_AA, en_aa);
|
||||
|
||||
if (status < 0) {
|
||||
return status;
|
||||
}
|
||||
|
||||
count_retrans = (count_retrans < 16) ? count_retrans : 15;
|
||||
|
||||
/* setup auto retransmit delay and count */
|
||||
return nrf24l01p_write_reg(dev, REG_SETUP_RETR, ((delay_retrans << 4) | count_retrans));
|
||||
}
|
||||
|
||||
int nrf24l01p_disable_all_auto_ack(nrf24l01p_t *dev)
|
||||
{
|
||||
return nrf24l01p_write_reg(dev, REG_EN_AA, 0x00);
|
||||
}
|
||||
|
||||
|
||||
int nrf24l01p_flush_tx_fifo(nrf24l01p_t *dev)
|
||||
{
|
||||
int status;
|
||||
char reg_content;
|
||||
|
||||
gpio_clear(dev->cs);
|
||||
hwtimer_spin(DELAY_CS_TOGGLE_TICKS);
|
||||
status = spi_transfer_byte(dev->spi, CMD_FLUSH_TX, ®_content);
|
||||
hwtimer_spin(DELAY_CS_TOGGLE_TICKS);
|
||||
gpio_set(dev->cs);
|
||||
|
||||
hwtimer_spin(DELAY_AFTER_FUNC_TICKS);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
int nrf24l01p_flush_rx_fifo(nrf24l01p_t *dev)
|
||||
{
|
||||
int status;
|
||||
char reg_content;
|
||||
|
||||
gpio_clear(dev->cs);
|
||||
|
||||
hwtimer_spin(DELAY_CS_TOGGLE_TICKS);
|
||||
status = spi_transfer_byte(dev->spi, CMD_FLUSH_RX, ®_content);
|
||||
hwtimer_spin(DELAY_CS_TOGGLE_TICKS);
|
||||
gpio_set(dev->cs);
|
||||
|
||||
hwtimer_spin(DELAY_AFTER_FUNC_TICKS);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
void nrf24l01p_rx_cb(void *arg)
|
||||
{
|
||||
DEBUG("In HW cb\n");
|
||||
|
||||
nrf24l01p_t *dev = (nrf24l01p_t *)arg;
|
||||
|
||||
/* clear interrupt */
|
||||
nrf24l01p_reset_all_interrupts(dev);
|
||||
|
||||
/* informs thread about available rx data*/
|
||||
if (dev->listener != KERNEL_PID_UNDEF) {
|
||||
msg_t m;
|
||||
m.type = RCV_PKT_NRF24L01P;
|
||||
m.content.ptr = (char *)dev;
|
||||
/* transmit more things here ? */
|
||||
msg_send_int(&m, dev->listener);
|
||||
}
|
||||
}
|
30
tests/driver_nrf24l01p_lowlevel/Makefile
Normal file
30
tests/driver_nrf24l01p_lowlevel/Makefile
Normal file
@ -0,0 +1,30 @@
|
||||
APPLICATION = driver_nrf24l01p_lowlevel
|
||||
include ../Makefile.tests_common
|
||||
|
||||
USEMODULE += shell
|
||||
USEMODULE += shell_commands
|
||||
USEMODULE += ps
|
||||
USEMODULE += vtimer
|
||||
USEMODULE += nrf24l01p
|
||||
|
||||
FEATURES_REQUIRED = periph_spi
|
||||
|
||||
SPI_PORT ?= SPI_0
|
||||
CE_PIN ?= GPIO_8
|
||||
CS_PIN ?= GPIO_7
|
||||
IRQ_PIN ?= GPIO_6
|
||||
|
||||
include $(RIOTBASE)/Makefile.include
|
||||
|
||||
ifneq (,$(SPI_PORT))
|
||||
export CFLAGS += -DSPI_PORT=$(SPI_PORT)
|
||||
endif
|
||||
ifneq (,$(CE_PIN))
|
||||
export CFLAGS += -DCE_PIN=$(CE_PIN)
|
||||
endif
|
||||
ifneq (,$(CS_PIN))
|
||||
export CFLAGS += -DCS_PIN=$(CS_PIN)
|
||||
endif
|
||||
ifneq (,$(IRQ_PIN))
|
||||
export CFLAGS += -DIRQ_PIN=$(IRQ_PIN)
|
||||
endif
|
94
tests/driver_nrf24l01p_lowlevel/README.md
Normal file
94
tests/driver_nrf24l01p_lowlevel/README.md
Normal file
@ -0,0 +1,94 @@
|
||||
# Test for nrf24l01p lowlevel functions
|
||||
|
||||
## About
|
||||
This is a small test application to see how the lowlevel-driver functions of the proprietary nrf24l01p-transceiver work. These functions consist of general SPI and GPIO commands, which abstract the driver-functions from the used board. In order to build this application, you need to add the board to the Makefile's `WHITELIST` first and define a pin mapping.
|
||||
|
||||
## Predefined pin mapping
|
||||
Please compare the `tests/driver_nrf24l01p_lowlevel/Makefile` for predefined pin-mappings on different boards. (In addition, you also need to connect to 3V and GND)
|
||||
|
||||
## Usage
|
||||
You should be presented with the RIOT shell, providing you with commands to initialize the transceiver (command: `it`), sending one packet (command: `send`) or read out and print all registers of the transceiver as binary values (command: `prgs`).
|
||||
|
||||
### Procedure
|
||||
* take two boards and connect a transceiver to each
|
||||
(it should be also possible to use one board with different SPI-ports)
|
||||
* depending on your board, you'll maybe also need to connect a UART/tty converter
|
||||
* build and flash the test-program to each
|
||||
* open a terminal (e.g. pyterm) for each
|
||||
* if possible, reset the board by using the reset-button. You'll see "_Welcome to RIOT_" etc.
|
||||
* type `help` to see the description of the commands
|
||||
* initialize both with `it`
|
||||
* with one board, send a packet by typing `send`
|
||||
* in the next step you can also use `send` to send data in the other direction
|
||||
* now you can use send on both boards/transceivers to send messages between them
|
||||
|
||||
|
||||
## Expected Results
|
||||
After you did all steps described above, you should see that a 32 Byte sequence (numbers from 32...1) has been transferred from one device to the other. This sequence is printed out from the receiver after the receive interrupt occurred and the receive-procedure has been made.
|
||||
|
||||
After initialization (`it`) you should see the following output:
|
||||
|
||||
```
|
||||
> it
|
||||
|
||||
Init Transceiver
|
||||
|
||||
Registering nrf24l01p_rx_handler thread...
|
||||
################## Print Registers ###################
|
||||
REG_CONFIG:
|
||||
0x0 returned: 00111111
|
||||
|
||||
REG_EN_AA:
|
||||
0x1 returned: 00000001
|
||||
|
||||
REG_EN_RXADDR:
|
||||
0x2 returned: 00000011
|
||||
|
||||
REG_SETUP_AW:
|
||||
0x3 returned: 00000011
|
||||
|
||||
REG_SETUP_RETR:
|
||||
0x4 returned: 00101111
|
||||
|
||||
REG_RF_CH:
|
||||
0x5 returned: 00000101
|
||||
|
||||
REG_RF_SETUP:
|
||||
0x6 returned: 00100111
|
||||
|
||||
REG_STATUS:
|
||||
0x7 returned: 00001110
|
||||
|
||||
REG_OBSERVE_TX:
|
||||
0x8 returned: 00000000
|
||||
|
||||
REG_RPD:
|
||||
0x9 returned: 00000000
|
||||
|
||||
REG_RX_ADDR_P0:
|
||||
0xa returned: e7 e7 e7 e7 e7
|
||||
|
||||
REG_TX_ADDR:
|
||||
0x10 returned: e7 e7 e7 e7 e7
|
||||
|
||||
REG_RX_PW_P0:
|
||||
0x11 returned: 00100000
|
||||
|
||||
REG_FIFO_STATUS:
|
||||
0x17 returned: 00010001
|
||||
|
||||
REG_DYNPD:
|
||||
0x1c returned: 00000000
|
||||
|
||||
REG_FEATURE:
|
||||
0x1d returned: 00000000
|
||||
|
||||
```
|
||||
|
||||
After the data has been sent (`send`), you should see the following output on the receiver terminal:
|
||||
```
|
||||
In HW cb
|
||||
nrf24l01p_rx_handler got a message: Received packet.
|
||||
32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1
|
||||
|
||||
```
|
331
tests/driver_nrf24l01p_lowlevel/main.c
Normal file
331
tests/driver_nrf24l01p_lowlevel/main.c
Normal file
@ -0,0 +1,331 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Hamburg University of Applied Sciences
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser General
|
||||
* Public License v2.1. See the file LICENSE in the top level directory for more
|
||||
* details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ingroup tests
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief Test application for nrf24l01p lowlevel functions
|
||||
*
|
||||
* @author Peter Kietzmann <peter.kietzmann@haw-hamburg.de>
|
||||
*
|
||||
* @}
|
||||
*/
|
||||
|
||||
#ifndef SPI_PORT
|
||||
#error "SPI_PORT not defined"
|
||||
#endif
|
||||
#ifndef CE_PIN
|
||||
#error "CE_PIN not defined"
|
||||
#endif
|
||||
#ifndef CS_PIN
|
||||
#error "CS_PIN not defined"
|
||||
#endif
|
||||
#ifndef IRQ_PIN
|
||||
#error "IRQ_PIN not defined"
|
||||
#endif
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <inttypes.h>
|
||||
#include <board.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "nrf24l01p.h"
|
||||
#include "nrf24l01p_settings.h"
|
||||
#include "periph/spi.h"
|
||||
#include "periph/gpio.h"
|
||||
#include "vtimer.h"
|
||||
#include "hwtimer.h"
|
||||
#include "shell.h"
|
||||
#include "shell_commands.h"
|
||||
#include "thread.h"
|
||||
#include "msg.h"
|
||||
|
||||
#define TEST_RX_MSG 1
|
||||
|
||||
#define SHELL_BUFFER_SIZE 128
|
||||
|
||||
static int shell_read(void);
|
||||
static void shell_write(int);
|
||||
static void cmd_send(int argc, char **argv);
|
||||
static void cmd_print_regs(int argc, char **argv);
|
||||
static void cmd_its(int argc, char **argv);
|
||||
|
||||
|
||||
void printbin(unsigned byte);
|
||||
void print_register(char reg, int num_bytes);
|
||||
|
||||
|
||||
static nrf24l01p_t nrf24l01p_0;
|
||||
|
||||
/**
|
||||
* define some additional shell commands
|
||||
*/
|
||||
static const shell_command_t shell_commands[] = {
|
||||
{ "prgs", "print registers", cmd_print_regs },
|
||||
{ "it", "init transceiver", cmd_its },
|
||||
{ "send", "send 32 bytes data", cmd_send },
|
||||
{ NULL, NULL, NULL }
|
||||
};
|
||||
|
||||
void prtbin(unsigned byte)
|
||||
{
|
||||
for (char i = 0; i < 8; i++) {
|
||||
printf("%u", (byte >> (7 - i)) & 0x0001);
|
||||
}
|
||||
|
||||
puts("\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* @print register
|
||||
*/
|
||||
void print_register(char reg, int num_bytes)
|
||||
{
|
||||
|
||||
vtimer_init();
|
||||
|
||||
char buf_return[num_bytes];
|
||||
int ret;
|
||||
|
||||
|
||||
gpio_clear(CS_PIN);
|
||||
vtimer_usleep(1);
|
||||
ret = spi_transfer_regs(SPI_PORT, (CMD_R_REGISTER | (REGISTER_MASK & reg)), 0, buf_return, num_bytes);
|
||||
gpio_set(CS_PIN);
|
||||
|
||||
if (ret < 0) {
|
||||
printf("Error in read access\n");
|
||||
}
|
||||
else {
|
||||
if (num_bytes < 2) {
|
||||
printf("0x%x returned: ", reg);
|
||||
|
||||
for (int i = 0; i < num_bytes; i++) {
|
||||
prtbin(buf_return[i]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
printf("0x%x returned: ", reg);
|
||||
|
||||
for (int i = 0; i < num_bytes; i++) {
|
||||
printf("%x ", buf_return[i]);
|
||||
}
|
||||
|
||||
printf("\n\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
char rx_handler_stack[KERNEL_CONF_STACKSIZE_MAIN];
|
||||
|
||||
/* RX handler that waits for a message from the ISR */
|
||||
void *nrf24l01p_rx_handler(void *arg)
|
||||
{
|
||||
msg_t msg_q[1];
|
||||
msg_init_queue(msg_q, 1);
|
||||
unsigned int pid = thread_getpid();
|
||||
char rx_buf[NRF24L01P_MAX_DATA_LENGTH];
|
||||
|
||||
puts("Registering nrf24l01p_rx_handler thread...");
|
||||
nrf24l01p_register(&nrf24l01p_0, &pid);
|
||||
|
||||
msg_t m;
|
||||
|
||||
while (msg_receive(&m)) {
|
||||
printf("nrf24l01p_rx_handler got a message: ");
|
||||
|
||||
switch (m.type) {
|
||||
case RCV_PKT_NRF24L01P:
|
||||
puts("Received packet.");
|
||||
|
||||
/* CE low */
|
||||
nrf24l01p_stop((nrf24l01p_t *)m.content.ptr);
|
||||
|
||||
/* read payload */
|
||||
nrf24l01p_read_payload((nrf24l01p_t *)m.content.ptr, rx_buf, NRF24L01P_MAX_DATA_LENGTH);
|
||||
|
||||
/* flush rx fifo */
|
||||
nrf24l01p_flush_rx_fifo((nrf24l01p_t *)m.content.ptr);
|
||||
|
||||
/* CE high */
|
||||
nrf24l01p_start((nrf24l01p_t *)m.content.ptr);
|
||||
|
||||
/* print rx buffer */
|
||||
for (int i = 0; i < NRF24L01P_MAX_DATA_LENGTH; i++) {
|
||||
printf("%i ", rx_buf[i]);
|
||||
}
|
||||
|
||||
puts("");
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
puts("stray message.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
puts("nrf24l01p_rx_handler: this should not have happened!");
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @init transceiver
|
||||
*/
|
||||
void cmd_its(int argc, char **argv)
|
||||
{
|
||||
(void) argc;
|
||||
(void) argv;
|
||||
|
||||
puts("Init Transceiver\n");
|
||||
|
||||
nrf24l01p_init(&nrf24l01p_0, SPI_PORT, CE_PIN, CS_PIN, IRQ_PIN);
|
||||
|
||||
/* create thread that gets msg when data arrives */
|
||||
thread_create(
|
||||
rx_handler_stack, sizeof(rx_handler_stack), PRIORITY_MAIN - 1, 0,
|
||||
nrf24l01p_rx_handler, 0, "nrf24l01p_rx_handler");
|
||||
|
||||
/* setup device as receiver */
|
||||
nrf24l01p_set_rxmode(&nrf24l01p_0);
|
||||
|
||||
cmd_print_regs(0, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @set TX mode
|
||||
*/
|
||||
void cmd_send(int argc, char **argv)
|
||||
{
|
||||
(void) argc;
|
||||
(void) argv;
|
||||
|
||||
puts("Send");
|
||||
|
||||
int status = 0;
|
||||
char tx_buf[NRF24L01P_MAX_DATA_LENGTH];
|
||||
|
||||
/* fill TX buffer with numbers 32..1 */
|
||||
for (int i = 0; i < sizeof(tx_buf); i++) {
|
||||
tx_buf[i] = NRF24L01P_MAX_DATA_LENGTH - i;
|
||||
}
|
||||
/* power on the device */
|
||||
nrf24l01p_on(&nrf24l01p_0);
|
||||
/* setup device as transmitter */
|
||||
nrf24l01p_set_txmode(&nrf24l01p_0);
|
||||
/* load data to transmit into device */
|
||||
nrf24l01p_preload(&nrf24l01p_0, tx_buf, NRF24L01P_MAX_DATA_LENGTH);
|
||||
/* trigger transmitting */
|
||||
nrf24l01p_transmit(&nrf24l01p_0);
|
||||
/* wait while data is pysically transmitted */
|
||||
hwtimer_wait(DELAY_DATA_ON_AIR);
|
||||
|
||||
status = nrf24l01p_get_status(&nrf24l01p_0);
|
||||
if (status & TX_DS) {
|
||||
puts("Sent Packet");
|
||||
}
|
||||
/* setup device as receiver */
|
||||
nrf24l01p_set_rxmode(&nrf24l01p_0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @print registers
|
||||
*/
|
||||
void cmd_print_regs(int argc, char **argv)
|
||||
{
|
||||
(void) argc;
|
||||
(void) argv;
|
||||
|
||||
printf("################## Print Registers ###################\n");
|
||||
|
||||
|
||||
puts("REG_CONFIG: ");
|
||||
print_register(REG_CONFIG, 1);
|
||||
|
||||
puts("REG_EN_AA: ");
|
||||
print_register(REG_EN_AA, 1);
|
||||
|
||||
puts("REG_EN_RXADDR: ");
|
||||
print_register(REG_EN_RXADDR, 1);
|
||||
|
||||
puts("REG_SETUP_AW: ");
|
||||
print_register(REG_SETUP_AW, 1);
|
||||
|
||||
puts("REG_SETUP_RETR: ");
|
||||
print_register(REG_SETUP_RETR, 1);
|
||||
|
||||
puts("REG_RF_CH: ");
|
||||
print_register(REG_RF_CH, 1);
|
||||
|
||||
puts("REG_RF_SETUP: ");
|
||||
print_register(REG_RF_SETUP, 1);
|
||||
|
||||
puts("REG_STATUS: ");
|
||||
print_register(REG_STATUS, 1);
|
||||
|
||||
puts("REG_OBSERVE_TX: ");
|
||||
print_register(REG_OBSERVE_TX, 1);
|
||||
|
||||
puts("REG_RPD: ");
|
||||
print_register(REG_RPD, 1);
|
||||
|
||||
puts("REG_RX_ADDR_P0: ");
|
||||
print_register(REG_RX_ADDR_P0, INITIAL_ADDRESS_WIDTH);
|
||||
|
||||
puts("REG_TX_ADDR: ");
|
||||
print_register(REG_TX_ADDR, INITIAL_ADDRESS_WIDTH);
|
||||
|
||||
puts("REG_RX_PW_P0: ");
|
||||
print_register(REG_RX_PW_P0, 1);
|
||||
|
||||
puts("REG_FIFO_STATUS: ");
|
||||
print_register(REG_FIFO_STATUS, 1);
|
||||
|
||||
puts("REG_DYNPD: ");
|
||||
print_register(REG_DYNPD, 1);
|
||||
|
||||
puts("REG_FEATURE: ");
|
||||
print_register(REG_FEATURE, 1);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief proxy for reading a char from std-in and passing it to the shell
|
||||
*/
|
||||
int shell_read(void)
|
||||
{
|
||||
return (int) getchar();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief proxy for taking a character from the shell and writing it to std-out
|
||||
*/
|
||||
void shell_write(int c)
|
||||
{
|
||||
putchar((char)c);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
shell_t shell;
|
||||
|
||||
puts("Welcome to RIOT!");
|
||||
|
||||
puts("Initializing shell...");
|
||||
shell_init(&shell, shell_commands, SHELL_BUFFER_SIZE, shell_read,
|
||||
shell_write);
|
||||
|
||||
puts("Starting shell...");
|
||||
shell_run(&shell);
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue
Block a user