roboforum.ru

Технический форум по робототехнике.

nRF24L01+

nRF24L01+

elesy » 14 июл 2015, 13:08

Прикупил себе данные модули по 110 рублей.
Начинаю мучать в связке STM8S105.
Если кто с ними имел дело - прошу отписаться.
Потихоньку буду в первом посте выкладывать код
Код: Выделить всёРазвернуть
/*
********************************************************************************
** File   : nrf24l01+.h
** Date   : 07.07.2015
** Autors :
** Notes  :
********************************************************************************
*/
#ifndef __NRF24L01_PLUS_H__
#define __NRF24L01_PLUS_H__

#include "stm8s.h"
#include "gpio.h"
#include "spi.h"
#include "delay.h"
#include "led.h"


/*
Распиновка модуля
    1 - 3.3V
    2 - gnd
    3 - CE
    4 - CSn
    5 - SCK
    6 - MOSI
    7 - MISO
    8 - IRQ

    CN2->4      PC3                     3
    CN2->5      PC4                     4
    CN2->6      PC5->SPI_CLK            5
    CN2->7      gnd                     2
    CN2->8      +3.3V                   1
    CN2->9      PC6->SPI_MOSI           6
    CN2->10     PC7->SPI_MISO           7

    CN4->8      PD3                     8
*/

/*
********************************************************************************
**                       Definitions
********************************************************************************
*/
/* PC4 - Chip Select                                                          */
#define CSN_GPIO  GPIOC
#define CSN_PIN   GPIO_PIN_4
#define RF_CSN_PIN CSN_GPIO, CSN_PIN

/* PC3 - CE                                                                   */
#define CE_GPIO   GPIOC
#define CE_PIN    GPIO_PIN_3
#define RF_CE_PIN CE_GPIO, CE_PIN

/* SPI                                                                        */
/* PC5 - SPI_SCK                                                              */
/* PC6 - SPI_MOSI                                                             */
/* PC7 - SPI_MISO                                                             */

/* PD3 - IRQ                                                                  */
#define IRQ_GPIO  GPIOD
#define IRQ_PIN   GPIO_PIN_3
#define RF_IRQ_PIN IRQ_GPIO, IRQ_PIN

#define Config_Reg_Reset_Value           0x0E
#define Max_Data_Len          32   //maximum Bytes in Payload, typ. 32
#define Max_Adress_Len          5   //maximum Bytes in Data Adress, typ. 5
#define Init_Delay_us          4000    //useconds wait for init chip delay, typ. 4000us
#define Payload_send_delay      40000   //maximum delay in cycles for data send ready in case of error

/* nRF24L01 адреса регистров                                                  */
#define CONFIG_REG                0x00
#define EN_AA_REG                 0x01
#define EN_RXADDR_REG             0x02
#define SETUP_AW_REG              0x03
#define SETUP_RETR_REG            0x04
#define RF_CH_REG                 0x05
#define RF_SETUP_REG              0x06
#define STATUS_REG                0x07
#define OBSERVE_TX_REG            0x08
#define RPD_REG                   0x09
#define RX_ADDR_P0_REG            0x0A
#define RX_ADDR_P1_REG            0x0B
#define RX_ADDR_P2_REG            0x0C
#define RX_ADDR_P3_REG            0x0D
#define RX_ADDR_P4_REG            0x0E
#define RX_ADDR_P5_REG            0x0F
#define TX_ADDR_REG               0x10
#define RX_PW_P0_REG              0x11
#define RX_PW_P1_REG              0x12
#define RX_PW_P2_REG              0x13
#define RX_PW_P3_REG              0x14
#define RX_PW_P4_REG              0x15
#define RX_PW_P5_REG              0x16
#define FIFO_STATUS_REG           0x17
#define DYNPD_REG                 0x1C

/* nRF24L01 команды                                                           */
#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_NOP                   0xFF  // команда заглушка, ничего не делает.


/* Биты регистра CONFIG                                                       */
#define CONFIG_MASK_RX_DR  6 //вкл/откл прерывание от бита RX_DR в рег. STATUS. 0-вкл, 1-выкл.
#define CONFIG_MASK_TX_DS  5 //вкл/откл прерывание от бита TX_DS в рег. STATUS. 0-вкл, 1-выкл.
#define CONFIG_MASK_MAX_RT 4 //вкл/откл прерывание от бита MAX_RT в рег. STATUS. 0-вкл, 1-выкл.
#define CONFIG_EN_CRC      3 //включение CRC. По умолчанию вкл. если один из битов регистра EN_AA включен.
#define CONFIG_CRCO        2 //режим CRC. 0-1 байт, 1-2 байта.
#define CONFIG_PWR_UP      1 //1-POWER UP, 0-POWER DOWN, по умолчанию 0.
#define CONFIG_PRIM_RX     0 //0-режим передачи, 1-режим приема.

/* Биты регистра STATUS                                                       */
#define STATUS_RX_DR        6 /*прерывание: данные получены. Для сброса записать 1.*/
#define STATUS_TX_DS        5 /*прерывание: данные переданы. Для сброса записать 1.*/
#define STATUS_MAX_RT       4 /*прерывание: данные не переданы. Для сброса записать 1.*/
#define STATUS_RX_P_NO2     3
#define STATUS_RX_P_NO1     2
#define STATUS_RX_P_NO0     1
#define STATUS_TX_FULL0     0 /*флаг переполнения TX FIFO буфера передачи. */
                              /* 1-переполнен, 0-есть еще место.*/

/*
********************************************************************************
**                       Constants
********************************************************************************
*/

/*
********************************************************************************
**                       Typedefs
********************************************************************************
*/
//#pragma bitfields = reversed
//
//typedef struct _nrf_reg_CONFIG_content {
//    uint8_t reserved : 1;
//    uint8_t MASK_RX_DX : 1;
//} nrf_reg_CONFIG_content;

typedef struct _nrf_reg_ {
    uint8_t Config;
    uint8_t EN_AA;
    uint8_t En_RxAddr;
    uint8_t Setup_AW;
    uint8_t Setup_RETR;
    uint8_t RF_Chahell;
    uint8_t RF_Setup;
    uint8_t Status;
    uint8_t observe_Tx;
    uint8_t RPD;
    uint8_t Rx_Addr_Pipe0[5];
    uint8_t Rx_Addr_Pipe1[5];
    uint8_t Rx_Addr_Pipe2[5];
    uint8_t Rx_Addr_Pipe3[5];
    uint8_t Rx_Addr_Pipe4[5];
    uint8_t Rx_Addr_Pipe5[5];
    uint8_t Tx_Addr[5];
    uint8_t Rx_Pw_Pipe0;
    uint8_t Rx_Pw_Pipe1;
    uint8_t Rx_Pw_Pipe2;
    uint8_t Rx_Pw_Pipe3;
    uint8_t Rx_Pw_Pipe4;
    uint8_t Rx_Pw_Pipe5;
    uint8_t FIFO_Status;
} _nrf_reg;
/*
********************************************************************************
**                       Variables
********************************************************************************
*/
extern _nrf_reg  nrf_reg;
/*
********************************************************************************
**                       Function prototypes
********************************************************************************
*/
void nrf24l01_SendCommand ( uint8_t cmd );
void nrf24l01_WriteRegister ( uint8_t address, uint8_t *value, uint8_t length );
uint8_t nrf24l01_ReadRegister ( uint8_t address );
void nrf24l01_SendAddress ( uint8_t address, uint8_t cmd[Max_Adress_Len] );

void nrf24l01_Init ( void );
void nrf24l01_Setup ( void );

void nrf24l01_ReadAllRegister ( void );
void nrf24l01_WriteAllRegister ( void );

void nrf24l01_prx ( void );
void nrf24l01_ptx ( void );
void nrf24l01_standby ( void );
void nrf24l01_PowerDown ( void );
void nrf24l01_SetTxLength ( uint8_t l );
void nrf24l01_ClearInterrupts ( void );

void RF_SendByte ( uint8_t data );
uint8_t RF_ReceiveByte ( void );

void nrf24l01_FirstStart ( void );

#endif



Код: Выделить всёРазвернуть
/*
********************************************************************************
** File   : nrf24l01+.c
** Date   : 07.07.2015
** Autors :
** Notes  :
********************************************************************************
*/
#include "nrf24l01+.h"

/*$PAGE$*/
/*
********************************************************************************
** Descriptions :
** Parameter    :
** Return       :
** Notes        :
********************************************************************************
*/
void nrf24l01_SendCommand ( uint8_t cmd )
{
    PIN_OFF ( CSN_GPIO, CSN_PIN );  // PC.4 = 0
   
    while ( SPI_GetFlagStatus ( SPI_FLAG_TXE ) == RESET );
    SPI_SendData ( cmd );
    while ( SPI_GetFlagStatus ( SPI_FLAG_BSY ) == SET );
    while ( SPI_GetFlagStatus ( SPI_FLAG_RXNE ) == RESET );
    SPI_ReceiveData ();
   
    PIN_ON  ( CSN_GPIO, CSN_PIN );  // PC.4 = 1
}
/*$PAGE$*/
/*
********************************************************************************
** Descriptions :
** Parameter    :
** Return       :
** Notes        :
********************************************************************************
*/
void nrf24l01_WriteRegister ( uint8_t address, uint8_t *value, uint8_t length )
{
    uint8_t i = 0;
   
    PIN_OFF ( CSN_GPIO, CSN_PIN );      // PC.4 = 0
   
    //spi_SendByte ( address );
    //spi_SendByte ( value );
   
    //Send address and write command
    while ( SPI_GetFlagStatus ( SPI_FLAG_TXE ) == RESET );
    SPI_SendData ( CMD_W_REGISTER | address );
    while ( SPI_GetFlagStatus ( SPI_FLAG_BSY ) == SET );
    while ( SPI_GetFlagStatus ( SPI_FLAG_RXNE ) == RESET );
    SPI_ReceiveData();

    //Send data 
    for ( i = 0; i < length; i++ ) {
        while ( SPI_GetFlagStatus ( SPI_FLAG_TXE ) == RESET);
        SPI_SendData ( value[ i ] );
        while ( SPI_GetFlagStatus ( SPI_FLAG_BSY ) == SET );
        while ( SPI_GetFlagStatus ( SPI_FLAG_RXNE ) == RESET );
        SPI_ReceiveData();
    }
   
    PIN_ON ( CSN_GPIO, CSN_PIN );       // PC.4 = 1
}
/*$PAGE$*/
/*
********************************************************************************
** Descriptions :
** Parameter    :
** Return       :
** Notes        :
********************************************************************************
*/
uint8_t nrf24l01_ReadRegister ( uint8_t address )
{
    uint8_t retVal = 0;
   
    PIN_OFF ( CSN_GPIO, CSN_PIN );      // PC.4 = 0
   
    //retVal = spi_ReadByte ( address );
    //retVal = spi_ReadByte ( CMD_NOP );
   
    //Send address and read command
    while ( SPI_GetFlagStatus ( SPI_FLAG_TXE ) == RESET );
    SPI_SendData ( CMD_R_REGISTER | address );
    while ( SPI_GetFlagStatus ( SPI_FLAG_BSY ) == SET );
    while ( SPI_GetFlagStatus ( SPI_FLAG_RXNE ) == RESET );
    SPI_ReceiveData ();
 
    //Get data
    while ( SPI_GetFlagStatus( SPI_FLAG_TXE ) == RESET );
    SPI_SendData(0x00);
    while ( SPI_GetFlagStatus( SPI_FLAG_BSY )== SET );
    while ( SPI_GetFlagStatus ( SPI_FLAG_RXNE ) == RESET );
    retVal = SPI_ReceiveData ();
   
    PIN_ON ( CSN_GPIO, CSN_PIN );       // PC.4 = 1
    return retVal;
}
Вложения
MINI-NRF24L01.jpg
Распиновка
Sc0UwtwO0q8.jpg
Сами модули
Последний раз редактировалось elesy 14 июл 2015, 13:56, всего редактировалось 3 раз(а).

Re: nRF24L01+

Angel71 » 14 июл 2015, 13:16

отписался

Re: nRF24L01+

elesy » 14 июл 2015, 13:20

У меня сейчас проблема с приемом. Не могу принять данные. Играл и с номером канала и с идентификатором. У тебя получилось установить связь?

Re: nRF24L01+

Angel71 » 14 июл 2015, 13:29

да, разобрался со всем кроме регистра cd. или в этом клоне оно не реализовано или лыжи не едут, как он работает.

Re: nRF24L01+

elesy » 14 июл 2015, 13:31

Регистр CD есть в nRF24L01, а у меня nRF24L01+

Re: nRF24L01+

Angel71 » 14 июл 2015, 13:41

тоже +, а в даташите про нерабочесть cd нигде не встречал. ну то такое, не сильно он и нужен. всё-равно уровень сигнала не даёт.
в общем что бы не отвлекаться и где не запутаться или адреса не трогай или ставь как по даташиту. отрубай динамическую длину данных и пробуй. ну даташит бегло глянуть можно, но самое нужное это расписание регистров. можно даже распечатать, постоянно страницы листать утомительно. внимательно обрати внимание на то, как дёргаешь пины ce и csn. они очень мозговыносящие, если не так дёрнуть.

Re: nRF24L01+

holomrn » 14 июл 2015, 13:43

На казусе просто огромная ветка про эти нрф..

Re: nRF24L01+

elesy » 14 июл 2015, 13:47

holomrn писал(а):На казусе просто огромная ветка про эти нрф..

То что на кактусе не идет. И ответа я там не смог получить.

Добавлено спустя 51 секунду:
Angel71 писал(а):, постоянно страницы листать утомительно. внимательно обрати внимание на то, как дёргаешь пины ce и csn. они очень мозговыносящие, если не так дёрнуть.


Основной код выкладываю в первом посту

Re: nRF24L01+

Angel71 » 14 июл 2015, 13:50

надёргал пару ф-ий для примера
Код: Выделить всёРазвернуть
static const uint8_t CMD_R_REGISTER = 0x00;
static const uint8_t MASK_RW_REGISTER = 0x1F;
uint8_t NRF24::read_register(uint8_t reg)
{
   csnLow();
   SPI.transfer(CMD_R_REGISTER | (MASK_RW_REGISTER & reg));
   uint8_t result = SPI.transfer(0xff);
   csnHi();
   return result;
}
void NRF24::read_register(uint8_t reg, uint8_t *buf, uint8_t len)
{
   csnLow();
   status.value = SPI.transfer(CMD_R_REGISTER | (MASK_RW_REGISTER & reg));
   while (len--)
      *buf++ = SPI.transfer(0xff);
   csnHi();
}
void NRF24::write_register(uint8_t reg, uint8_t value)
{
   csnLow();
   SPI.transfer(CMD_W_REGISTER | (MASK_RW_REGISTER & reg));
   SPI.transfer(value);
   csnHi();
}
void NRF24::powerDown()
{
   reg_config.value = read_register(REG_CONFIG_ADDR);
   reg_config.bits.PWR_UP = false;
   write_register(REG_CONFIG_ADDR, reg_config.value);
   ceLow();
}

void NRF24::powerUp()
{
   reg_config.value = read_register(REG_CONFIG_ADDR);
   reg_config.bits.PWR_UP = true;
   write_register(REG_CONFIG_ADDR, reg_config.value);
   ceHi();
}
void NRF24::powerUpTx()
{
   //The TX mode is an active mode where the nRF24L01 transmits a packet. To enter this mode, the
   //nRF24L01 must have the PWR_UP bit set high, PRIM_RX bit set low, a payload in the TX FIFO and, a high
   //pulse on the CE for more than 10µs.
   //...
   //datasheet page 21

   reg_config.value = read_register(REG_CONFIG_ADDR);
   reg_config.bits.PWR_UP = true;
   reg_config.bits.PRIM_RX = 0;
   write_register(REG_CONFIG_ADDR, reg_config.value);
   //ceHi();
   //delay(10);
}
void NRF24::powerUpRx()
{
   //The RX mode is an active mode where the nRF24L01 radio is a receiver. To enter this mode, the
   //nRF24L01 must have the PWR_UP bit set high, PRIM_RX bit set high and the CE pin set high.
   //datasheet page 21
   ceLow();
   reg_config.value = read_register(REG_CONFIG_ADDR);
   reg_config.bits.PWR_UP = true;
   reg_config.bits.PRIM_RX = 1;
   write_register(REG_CONFIG_ADDR, reg_config.value);
   ceHi();
}
void NRF24::send(const uint8_t *buf, uint8_t len)
{
   ceLow();
   //len = min(len, payload_size);
   csnLow();
   SPI.transfer(CMD_W_TX_PAYLOAD);
   //SPI.transfer(CMD_W_ACK_PAYLOAD);
   for (int i = 0; i < len; i++) SPI.transfer(buf[i]);
   csnHi();
   ceHi();
   delay(15);
}
void NRF24::recieve(uint8_t* buf, uint8_t len)
{
   len = max(len, payload_size);
   csnLow();
   SPI.transfer(CMD_R_RX_PAYLOAD);
   for (int i = 0; i < 32; i++)
      buf[i] = SPI.transfer(0xff);
   csnHi();
}

на классах только делать... я либу переписал и о том, что оно выжрет чуть больше ожидаемого уже потом понял. хотя так удобней. в общем не рекомендую классы, а там сами думайте.
даташит читать нужно, толку от тех веток. чуть выше я написал, что адреса не трогай и отключи во всех регистрах динамическую длину пакетов, с ними сразу туго работать.

Re: nRF24L01+

elesy » 14 июл 2015, 13:54

Angel71 писал(а):н
даташит читать нужно, толку от тех веток. чуть выше я написал, что адреса не трогай и отключи во всех регистрах динамическую длину пакетов, с ними сразу туго работать.


Его читал и читаю. Лежит рядом распечататный. А в форум полез когда не пошло

Re: nRF24L01+

Angel71 » 14 июл 2015, 14:08

регистры сбрасываются только при отключении питания, сброса у чипа нет. перечитываете в даташите все регистры и смотрите, что инициализировать. чем меньше трогать, тем лучше, меньше запутаетесь.
если поможет, я примерно так в последний раз инициализировал, тут без динамической длины пакета (payload_size = 32)
Код: Выделить всёРазвернуть
   ceLow();
   csnHi();

   delay( 5 );

   reg_config.value = 0;
   reg_config.bits.PRIM_RX = 1;
   reg_config.bits.PWR_UP = 0;
   reg_config.bits.CRCO = 1;
   reg_config.bits.EN_CRC = 1;
   reg_config.bits.MASK_MAX_RT = 0; //0: Reflect MAX_RT as active low interrupt on the IRQ pin
   reg_config.bits.MASK_TX_DS = 0; //0: Reflect TX_DS as active low interrupt on the IRQ pin
   reg_config.bits.MASK_RX_DR = 0; //0: Reflect RX_DR as active low interrupt on the IRQ pin
   write_register(REG_CONFIG_ADDR, reg_config.value);

   //EN_AA - Enhanced ShockBurst
   write_register(REG_EN_AA_ADDR, 0x1F); //Enable auto acknowledgement data pipe 0-5
   //write_register(REG_EN_AA_ADDR, 0);

   write_register(REG_EN_RX_ADDR, 0x01); //Enable data pipe 0

   write_register(REG_SETUP_AW_ADDR, 0x01); //RX/TX Address field width, 0x03 - '11' – 5 bytes

   UNION_SETUP_RETR reg_setup_retr;
   reg_setup_retr.value = 0;
   reg_setup_retr.bits.ARC = 3; //Auto Retransmit Count. 0 - off
   reg_setup_retr.bits.ARD = 1; //Auto Retransmit Delay, 0001 – Wait 500µS
   write_register(REG_SETUP_RETR_ADDR, reg_setup_retr.value);

   setChannel(0);

   UNION_RF_SETUP reg_rf_setup;
   reg_rf_setup.value = 0;
   reg_rf_setup.bits.LNA_HCURR = 1;
   reg_rf_setup.bits.RF_PWR = (rf24_pa_dbm)0;// rf24_pa_dbm::RF24_PA_MIN;
   reg_rf_setup.bits.RF_DR = (rf24_datarate)0; // rf24_datarate::RF24_1MBPS;
   write_register(REG_RF_SETUP_ADDR, reg_rf_setup.value);

   status.value = 0x70;//1110000 - clear RX_DR, TX_DS, MAX_RT
   write_register(REG_STATUS_ADDR, status.value);

   uint8_t arr5[5] = { 0xE7, 0xE7, 0xE7, 0xE7, 0xE7 };
   //arr5[0] = 0xE7;
   //arr5[1] = 0xE7;
   //arr5[2] = 0xE7;
   //arr5[3] = 0xE7;
   //arr5[4] = 0xE7;
   write_register(REG_RX_ADDR_BASE, arr5, 3); //RX_ADDR_P0
   write_register(REG_TX_ADDR, arr5, 3); //TX_ADDR_P0
   arr5[0] = 0xC2;
   arr5[1] = 0xC2;
   arr5[2] = 0xC2;
   arr5[3] = 0xC2;
   arr5[4] = 0xC2;
   write_register(REG_RX_ADDR_BASE + 1, arr5, 3); //RX_ADDR_P1
   write_register(REG_RX_ADDR_BASE + 2, 0xC3); //RX_ADDR_P2
   write_register(REG_RX_ADDR_BASE + 3, 0xC4); //RX_ADDR_P3
   write_register(REG_RX_ADDR_BASE + 4, 0xC5); //RX_ADDR_P4
   write_register(REG_RX_ADDR_BASE + 5, 0xC6); //RX_ADDR_P5

   write_register(REG_RX_PW_P_ADDR_BASE, payload_size); //Number of bytes in RX payload in data pipe 0.
   write_register(REG_RX_PW_P_ADDR_BASE + 1, payload_size); //Number of bytes in RX payload in data pipe 1.
   write_register(REG_RX_PW_P_ADDR_BASE + 2, payload_size); //Number of bytes in RX payload in data pipe 2.
   write_register(REG_RX_PW_P_ADDR_BASE + 3, payload_size); //Number of bytes in RX payload in data pipe 3.
   write_register(REG_RX_PW_P_ADDR_BASE + 4, payload_size); //Number of bytes in RX payload in data pipe 4.
   write_register(REG_RX_PW_P_ADDR_BASE + 5, payload_size); //Number of bytes in RX payload in data pipe 5.

   flush_rx();
   flush_tx();

   write_register(REG_DYNPD_ADDR, 0); //Enable dynamic payload length. pipe 0-5 off

   UNION_FEATURE reg_feature;
   reg_feature.value = 0;
   reg_feature.bits.EN_DYN_ACK = 0; //Enables the W_TX_PAYLOAD_NOACK command
   reg_feature.bits.EN_ACK_PAY = 0; //Enables Payload with ACK
   reg_feature.bits.EN_DPL = 0; //Enables Dynamic Payload Length
   write_register(REG_DYNPD_ADDR, reg_feature.value);

у меня оно по прерыванию ноги irq данные считывает.
есть три весёлых бита: RX_DR, TX_DS, MAX_RT. с ними больше всего веселья в начале изучения модуля. при отладке отправки и получения лучше проверять и с отключенной и с включенной ф-ей автоподтверждения доставки пакета + поотправлять пакетики в никуда (просто второй модуль отключить).

Re: nRF24L01+

chu » 25 июл 2015, 11:54

В ветке Форт-система почти полностью описана работа с nRF24L01+.
Приведенный там код даже избыточен и предназначался для изучения этого модуля.
На примерах показан обмен (и обработка ошибочных пакетов), сканнер диапазонов и
измеритель дальности с использованием CD.
из отзыва европейского коллеги:
Andreas Wagner писал(а):...
After going back through the forum thread to collect some missing words and
making a few modifications to nRF24_init I got the scanner+ranger to work!

Your posting is godsend for my remote sensing network project as it saves
me much time.

Re: nRF24L01+

Angel71 » 25 июл 2015, 12:44

форт? да вы весельчак. работа модуля боле чем нормлаьно описана в спецификации, его нужно взять и внимательно читать. просто с небольшим примером кода это немного проще и быстрей.


cron
Rambler\'s Top100 Mail.ru counter