[NRF24L01+] Problem z komunikacją
: niedziela 09 wrz 2018, 16:13
Próbuję skomunikować ze sobą 2 płytki NUCLEO.
Odbiornik:
STM32L053R8
main.c:
Nadajnik
STM32F411RE
main.c
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.
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.