[NRF24L01+] Problem z komunikacją

Wszystko o co chcesz zapytać na temat mikrokontrolerów ARM firmy STMicroelectronics: problemy z pisaniem programu, problemy sprzętowe, niejasności w DS czy AN itp.
Awatar użytkownika
inż.wielki
User
User
Posty: 307
Rejestracja: niedziela 20 gru 2015, 23:11

[NRF24L01+] Problem z komunikacją

Postautor: inż.wielki » niedziela 09 wrz 2018, 16:13

Próbuję skomunikować ze sobą 2 płytki NUCLEO.

Odbiornik:
STM32L053R8
main.c:

Kod: Zaznacz cały

/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "stm32_hwinit.h"
#include "stdlib.h"
#include "string.h"
#include "stdio.h"

#include "nrf24.h"

uint32_t i,j,k;

// Buffer to store a payload of maximum width
uint8_t nRF24_payload[32];

// Pipe number
nRF24_RXResult pipe;

// Length of received payload
uint8_t payload_length;

void SystemClock_Config(void);
/* Private functions ---------------------------------------------------------*/

/**
  * @brief  Main program
  * @param  None
  * @retval None
  */
int main(void)
{
  /* Configure the system clock to 2.097 MHz */
  SystemClock_Config();
  STM32_HwInit();
  /* Add your application code here */
  dbg("Program start! (Compile: %s:%s)\r\n", __DATE__, __TIME__);

   // Initialize the nRF24L01 GPIO pins
    nRF24_GPIO_Init();

    // RX/TX disabled
    nRF24_CE_L();

    // Configure the nRF24L01+
    dbg("nRF24L01+ check: ");
    if (!nRF24_Check()) {
       dbg("FAIL\r\n");
       while (1);
    }
    dbg("OK\r\n");

    // Initialize the nRF24L01 to its default state
    nRF24_Init();

    // Configure the nRF24L01+
    dbg("nRF24L01+ check: ");
    if (!nRF24_Check2()) {
      dbg("FAIL\r\n");
      while (1);
    }
    dbg("OK\r\n");

    uint8_t ADDR[] = { 'n', 'R', 'F', '2', '4' }; // the address for RX pipe
    nRF24_SetRFChannel(90); // set RF channel to 2490MHz
    nRF24_SetDataRate(nRF24_DR_2Mbps); // 2Mbit/s data rate
    nRF24_SetCRCScheme(nRF24_CRC_2byte); // 1-byte CRC scheme
    nRF24_SetAddrWidth(5); // address width is 5 bytes
    nRF24_SetAddr(nRF24_PIPE1, ADDR); // program pipe address
    nRF24_SetRXPipe(nRF24_PIPE1, nRF24_AA_ON, 10); // enable RX pipe#1 with Auto-ACK: enabled, payload length: 10 bytes
    nRF24_SetTXPower(nRF24_TXPWR_12dBm); // configure TX power for Auto-ACK, good choice - same power level as on transmitter
    nRF24_SetOperationalMode(nRF24_MODE_RX); // switch transceiver to the RX mode
    nRF24_SetPowerMode(nRF24_PWR_UP); // wake-up transceiver (in case if it sleeping)

    // Put the transceiver to the RX mode
    nRF24_CE_H();
    dbg("Receiv start:\r\n");
    while(1) {
          //
      // Constantly poll the status of the RX FIFO and get a payload if FIFO is not empty
      //
      // This is far from best solution, but it's ok for testing purposes
      // More smart way is to use the IRQ pin :)
      //
      if (nRF24_GetStatus_RXFIFO() != nRF24_STATUS_RXFIFO_EMPTY) {
        // Get a payload from the transceiver
        pipe = nRF24_ReadPayload(nRF24_payload, &payload_length);

        // Clear all pending IRQ flags
        nRF24_ClearIRQFlags();

        // Print a payload contents to UART
        dbg("RCV PIPE#%d PAYLOAD:>", pipe);
        for(int i = 0; i < payload_length; i++) {
          dbg("0x%X ", nRF24_payload[i]);
        }
        dbg("<\r\n");
        LL_GPIO_TogglePin(LED2_GPIO_PORT, LED2_PIN); 
      }
    }
}

/* ==============   BOARD SPECIFIC CONFIGURATION CODE BEGIN    ============== */
/**
  * @brief  System Clock Configuration
  *         The system Clock is configured as follow :
  *            System Clock source            = MSI
  *            SYSCLK(Hz)                     = 2097000
  *            HCLK(Hz)                       = 2097000
  *            AHB Prescaler                  = 1
  *            APB1 Prescaler                 = 1
  *            APB2 Prescaler                 = 1
  *            Flash Latency(WS)              = 0
  *            Main regulator output voltage  = Scale3 mode
  * @retval None
  */
void SystemClock_Config(void)
{
   /* MSI configuration and activation */
   LL_RCC_PLL_Disable();
   /* Set new latency */
   LL_FLASH_SetLatency(LL_FLASH_LATENCY_1);

   LL_RCC_MSI_Enable();
   while(LL_RCC_MSI_IsReady() != 1)
   {
   };
   LL_RCC_MSI_SetRange(LL_RCC_MSIRANGE_5); 
   LL_RCC_MSI_SetCalibTrimming(0x0);

   /* Sysclk activation  */
   LL_RCC_SetAHBPrescaler(LL_RCC_SYSCLK_DIV_1);
   LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_MSI);
   while(LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_MSI)
   {
   };

   /* Set APB1 & APB2 prescaler*/
   LL_RCC_SetAPB1Prescaler(LL_RCC_APB1_DIV_1);
   LL_RCC_SetAPB2Prescaler(LL_RCC_APB2_DIV_1);

   /* Set systick to 1ms in using frequency set to 2MHz */
   LL_Init1msTick(2097000);

   /* Update CMSIS variable (which can be updated also through SystemCoreClockUpdate function) */
   LL_SetSystemCoreClock(2097000); 

   /* Enable Power Control clock */
   LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_PWR);
   /* The voltage scaling allows optimizing the power consumption when the device is
    clocked below the maximum system frequency, to update the voltage scaling value
    regarding system frequency refer to product datasheet.  */
   LL_PWR_SetRegulVoltageScaling(LL_PWR_REGU_VOLTAGE_SCALE3);
   /* Disable Power Control clock */
   LL_APB1_GRP1_DisableClock(LL_APB1_GRP1_PERIPH_PWR);
}
/* ==============   BOARD SPECIFIC CONFIGURATION CODE END      ============== */

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t* file, uint32_t line)
{
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d", file, line) */

  /* Infinite loop */
  while (1)
  {
  }
}
#endif

void USART_sendString(char * str)
{
  while(*str)
  {
    while(LL_USART_IsActiveFlag_TXE(USART1) == 0 );
    LL_USART_TransmitData8(USART1, *str++);
  }
}

void dbg(const char * format, ...)
{
   char dest[DEBUG_MSG_SIZE];
   va_list argptr;
   va_start(argptr, format);
   vsprintf(dest, format, argptr);
   va_end(argptr);

   USART_sendString(dest);
}



Nadajnik
STM32F411RE
main.c

Kod: Zaznacz cały

/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "stm32_hwinit.h"
#include "stdlib.h"
#include "string.h"
#include "stdio.h"
#include "nrf24.h"

void SystemClock_Config(void);
uint32_t i,j,k;

// Buffer to store a payload of maximum width
uint8_t nRF24_payload[32];

// Pipe number
nRF24_RXResult pipe;

// Length of received payload
uint8_t payload_length;

#define nRF24_WAIT_TIMEOUT         (uint32_t)0x000FFFFF

// Result of packet transmission
typedef enum {
   nRF24_TX_ERROR  = (uint8_t)0x00, // Unknown error
   nRF24_TX_SUCCESS,                // Packet has been transmitted successfully
   nRF24_TX_TIMEOUT,                // It was timeout during packet transmit
   nRF24_TX_MAXRT                   // Transmit failed with maximum auto retransmit count
} nRF24_TXResult;

nRF24_TXResult tx_res;

// Function to transmit data packet
// input:
//   pBuf - pointer to the buffer with data to transmit
//   length - length of the data buffer in bytes
// return: one of nRF24_TX_xx values
nRF24_TXResult nRF24_TransmitPacket(uint8_t *pBuf, uint8_t length);
/**
  * @brief  Main program
  * @param  None
  * @retval None
  */
int main(void)
{
    /* Configure the system clock to 100 MHz */
     SystemClock_Config();
   STM32_HwInit();
   /* Add your application code here */
   dbg("Program start! (Compile: %s:%s)\r\n", __DATE__, __TIME__);

   // Initialize the nRF24L01 GPIO pins
    nRF24_GPIO_Init();

    // RX/TX disabled
    nRF24_CE_L();

    // Configure the nRF24L01+
   dbg("nRF24L01+ check: ");
   if (!nRF24_Check()) {
      dbg("FAIL\r\n");
      while (1);
   }
   dbg("OK\r\n");
   
    // Initialize the nRF24L01 to its default state
    nRF24_Init();

    payload_length = 10;
    uint8_t ADDR[] = { 'n', 'R', 'F', '2', '4' }; // the TX address
    nRF24_SetRFChannel(90); // set RF channel to 2490MHz
    nRF24_SetDataRate(nRF24_DR_2Mbps); // 2Mbit/s data rate
    nRF24_SetCRCScheme(nRF24_CRC_2byte); // 1-byte CRC scheme
    nRF24_SetAddrWidth(5); // address width is 5 bytes
    nRF24_SetAddr(nRF24_PIPETX, ADDR); // program TX address
    nRF24_SetAddr(nRF24_PIPE0, ADDR); // program pipe#0 RX address, must be same as TX (for ACK packets)
    nRF24_SetTXPower(nRF24_TXPWR_12dBm); // configure TX power
    nRF24_SetAutoRetr(nRF24_ARD_2500us, 10); // configure auto retransmit: 10 retransmissions with pause of 2500s in between
    nRF24_EnableAA(nRF24_PIPE0); // enable Auto-ACK for pipe#0 (for ACK packets)
    nRF24_SetOperationalMode(nRF24_MODE_TX); // switch transceiver to the TX mode
    nRF24_SetPowerMode(nRF24_PWR_UP); // wake-up transceiver (in case if it sleeping)
    // the nRF24 is ready for transmission, upload a payload, then pull CE pin to HIGH and it will transmit a packet...
     // Some variables
    uint32_t packets_lost = 0; // global counter of lost packets
    uint8_t otx;
    uint8_t otx_plos_cnt; // lost packet count
    uint8_t otx_arc_cnt; // retransmit count

       // The main loop
    j = 0;
    while (1) {
      // Print a payload
      // dbg("********\r\nPAYLOAD:>");
      // Prepare data packet
      for (i = 0; i < payload_length; i++) {
        nRF24_payload[i] = j++;
        // dbg("0x%X", j-1);
        if (j > 0x000000FF) j = 0;
      }
      //dbg("TX: ");

      // Transmit a packet
      tx_res = nRF24_TransmitPacket(nRF24_payload, payload_length);
      otx = nRF24_GetRetransmitCounters();
      otx_plos_cnt = (otx & nRF24_MASK_PLOS_CNT) >> 4; // packets lost counter
      otx_arc_cnt = (otx & nRF24_MASK_ARC_CNT); // auto retransmissions counter
      switch (tx_res) {
      case nRF24_TX_SUCCESS:
        dbg("TX: OK");
        break;
      case nRF24_TX_TIMEOUT:
        dbg("TIMEOUT");
        break;
      case nRF24_TX_MAXRT:
        dbg("MAX RETRANSMIT");
        packets_lost += otx_plos_cnt;
        nRF24_ResetPLOS();
        //dbg("\tARC=%d LOST=%d\r\n********\r\n", otx_arc_cnt, packets_lost);
        break;
      default:
        dbg("ERROR");
        break;
      }
      dbg("\r\n");
      if(tx_res == nRF24_TX_SUCCESS) {
        dbg("PAYLOAD:>");
        // Prepare data packet
        for (i = 0; i < payload_length; i++) {
           dbg("0x%X ", nRF24_payload[i]);
        }
        dbg("<\r\n");
      }
      // Wait ~0.5s
      LL_mDelay(500);
      LL_GPIO_TogglePin(LED2_GPIO_PORT, LED2_PIN);
    }
}

 
/* ==============   BOARD SPECIFIC CONFIGURATION CODE BEGIN    ============== */
/**
  * @brief  System Clock Configuration
  *         The system Clock is configured as follow :
  *            System Clock source            = PLL (HSE)
  *            SYSCLK(Hz)                     = 100000000
  *            HCLK(Hz)                       = 100000000
  *            AHB Prescaler                  = 1
  *            APB1 Prescaler                 = 2
  *            APB2 Prescaler                 = 1
  *            HSE Frequency(Hz)              = 8000000
  *            PLL_M                          = 8
  *            PLL_N                          = 400
  *            PLL_P                          = 4
  *            VDD(V)                         = 3.3
  *            Main regulator output voltage  = Scale1 mode
  *            Flash Latency(WS)              = 3
  * @param  None
  * @retval None
  */
void SystemClock_Config(void)
{
  /* Enable HSE oscillator */
  LL_RCC_HSE_EnableBypass();
  LL_RCC_HSE_Enable();
  while(LL_RCC_HSE_IsReady() != 1)
  {
  };

  /* Set FLASH latency */
  LL_FLASH_SetLatency(LL_FLASH_LATENCY_3);

  /* Main PLL configuration and activation */
  LL_RCC_PLL_ConfigDomain_SYS(LL_RCC_PLLSOURCE_HSE, LL_RCC_PLLM_DIV_8, 400, LL_RCC_PLLP_DIV_4);
  LL_RCC_PLL_Enable();
  while(LL_RCC_PLL_IsReady() != 1)
  {
  };

  /* Sysclk activation on the main PLL */
  LL_RCC_SetAHBPrescaler(LL_RCC_SYSCLK_DIV_1);
  LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_PLL);
  while(LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_PLL)
  {
  };

  /* Set APB1 & APB2 prescaler */
  LL_RCC_SetAPB1Prescaler(LL_RCC_APB1_DIV_2);
  LL_RCC_SetAPB2Prescaler(LL_RCC_APB2_DIV_1);

  /* Set systick to 1ms */
  SysTick_Config(100000000 / 1000);

  /* Update CMSIS variable (which can be updated also through SystemCoreClockUpdate function) */
  SystemCoreClock = 100000000;
}

/* ==============   BOARD SPECIFIC CONFIGURATION CODE END      ============== */

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t* file, uint32_t line)
{
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d", file, line) */

  /* Infinite loop */
  while (1)
  {
  }
}
#endif

void USART_sendString(char * str)
{
  while(*str)
  {
    while(LL_USART_IsActiveFlag_TXE(USARTx_INSTANCE) == 0 );
    LL_USART_TransmitData8(USARTx_INSTANCE, *str++);
  }
}

void dbg(const char * format, ...)
{
   char dest[DEBUG_MSG_SIZE];
   va_list argptr;
   va_start(argptr, format);
   vsprintf(dest, format, argptr);
   va_end(argptr);

   USART_sendString(dest);
}


nRF24_TXResult nRF24_TransmitPacket(uint8_t *pBuf, uint8_t length) {
  volatile uint32_t wait = nRF24_WAIT_TIMEOUT;
  uint8_t status;

  // Deassert the CE pin (in case if it still high)
  nRF24_CE_L();

  // Transfer a data from the specified buffer to the TX FIFO
  nRF24_WritePayload(pBuf, length);

  // Start a transmission by asserting CE pin (must be held at least 10us)
  nRF24_CE_H();

  // Poll the transceiver status register until one of the following flags will be set:
  //   TX_DS  - means the packet has been transmitted
  //   MAX_RT - means the maximum number of TX retransmits happened
  // note: this solution is far from perfect, better to use IRQ instead of polling the status
  do {
    status = nRF24_GetStatus();
    if (status & (nRF24_FLAG_TX_DS | nRF24_FLAG_MAX_RT)) {
      break;
    }
  } while (wait--);

  // Deassert the CE pin (Standby-II --> Standby-I)
  nRF24_CE_L();

  if (!wait) {
    // Timeout
    return nRF24_TX_TIMEOUT;
  }

  // Check the flags in STATUS register
  // dbg("[0x%X]\r\n", status);

  // Clear pending IRQ flags
    nRF24_ClearIRQFlags();

  if (status & nRF24_FLAG_MAX_RT) {
    // Auto retransmit counter exceeds the programmed maximum limit (FIFO is not removed)
    return nRF24_TX_MAXRT;
  }

  if (status & nRF24_FLAG_TX_DS) {
    // Successful transmission
    return nRF24_TX_SUCCESS;
  }

  // Some banana happens, a payload remains in the TX FIFO, flush it
  nRF24_FlushTX();

  return nRF24_TX_ERROR;
}



Korzystam z tej biblioteki https://github.com/LonelyWolf/stm32/tre ... r/nrf24l01
Udało mi się zestawić połączenie pomiędzy nimi w momencie kiedy ustawiłem długoś payload'u na 5bajtów. Ale nawet w tym wypadku ostatni bajt jest taki sam jak bajt nr4. Po zmianie długości pakietu na 10bajtów komunikacja umiera...

Próbowałem trybu z ShockBurst jak i bez niego. W obu przypadkach zachowanie jest dokładnie takie samo jak zostało opisane wyżej. Może ktoś ze świeżym oczkiem znajdzie jakiś błąd.

Awatar użytkownika
j23
Expert
Expert
Posty: 536
Rejestracja: czwartek 08 paź 2015, 18:40

Re: [NRF24L01+] Problem z komunikacją

Postautor: j23 » niedziela 09 wrz 2018, 17:46

Nie mogę tego parametru znaleźć w Twoim kodzie, ale to jest komunikacja typu full duplex (obie strony) czy half duplex (obie strony)?
Prędkości transmisji wydają się być takie same, więc coś musi być dalej, chyba że... to błąd fizyczny (zwarcie, przerwa w obwodzie)?
Internet łączy ludzi, którzy dzielą się swoimi zainteresowaniami, pomysłami i potrzebami, bez względu na geograficzne (przeciwności).
BOB TAYLOR, PARC

Awatar użytkownika
inż.wielki
User
User
Posty: 307
Rejestracja: niedziela 20 gru 2015, 23:11

Re: [NRF24L01+] Problem z komunikacją

Postautor: inż.wielki » niedziela 09 wrz 2018, 18:19

Transmisja jest od nadajnika do odbiornika, tam po sprawdzeniu poprawności danych jest wysylane ACK do nadajnika

Awatar użytkownika
j23
Expert
Expert
Posty: 536
Rejestracja: czwartek 08 paź 2015, 18:40

Re: [NRF24L01+] Problem z komunikacją

Postautor: j23 » niedziela 09 wrz 2018, 20:39

inż.wielki pisze:Transmisja jest od nadajnika do odbiornika, tam po sprawdzeniu poprawności danych jest wysylane ACK do nadajnika

Tzn. że jest taki uproszczony half duplex. Tylko, że jak ja patrzałem do tego kodu to przy całym tym protokole transmisji jest trochę namieszane, tzn.żeby transmisja była efektywna powinny być stosowane jakieś mechanizmy semaforów (flag kontroli transmisji), żeby było wiadome, czy np.pasmo transmisji jest wolne, czy ktoś nadaje (czasy minimalne i maksymalne nadawania/odbioru) - to na każdym etapie transmisji, a nie że sru, lecą dane i odbierze to ok (wysyła ACK), a jak jakaś kolizja (jednoczesne nadawanie dwóch urządzeń) to nie wiem jaki jest przewidziany mechanizm kontroli transmisji czy obsługi błędów (jakaś maksymalna ilość prób wysłania danych, komunikat o błędzie w nadawaniu?)...
Internet łączy ludzi, którzy dzielą się swoimi zainteresowaniami, pomysłami i potrzebami, bez względu na geograficzne (przeciwności).
BOB TAYLOR, PARC

Awatar użytkownika
inż.wielki
User
User
Posty: 307
Rejestracja: niedziela 20 gru 2015, 23:11

Re: [NRF24L01+] Problem z komunikacją

Postautor: inż.wielki » niedziela 09 wrz 2018, 21:01

Szczerze powiedziawszy liczyłem że to będzie plug&play i po prostu zaciągnąłem liba, przeportowałem i odpaliłem. Komunikacja jest jaka jest. Własnie w tym jest problem. Teraz chyba zabiorę się za napisanie liba.

Ale dzięki za punkt do zaczepienia

Edit: Problem rozwiązany, chodziło o komunikację SPI. Na programowym SPI wszystko działa jak złoto, po przestawieniu prędkościu pinów na medium również. Prawdopodobnie chodziło o efekt "dzwonienia" pinów przy zbyt szybkim ustalaniu stanu na pinie


Wróć do „ARM STMicroelectronics”

Kto jest online

Użytkownicy przeglądający to forum: Obecnie na forum nie ma żadnego zarejestrowanego użytkownika i 4 gości