2023-12-06 10:12 AM
I have 2 NUCLEO-WL55JC1 boards I am using to communicate using LoRa. The Tx board sends a message every 10 seconds, the Rx board receives the message and lights up an LED..I have this working at SF7, the same spreading factor as the ping-pong example I copied the code from, but if I try to change this to SF12 (on both Tx and Rx projects) the Rx board never receives messages.
Any ideas on how I can fix this? Her is the code
#include <stdio.h>
#include <radio_driver.h>
#include "types.h"
#include "radio.h"
#define RF_FREQUENCY 924000000 /* Hz */
#define TX_OUTPUT_POWER 14 /* dBm */
#define LORA_BANDWIDTH LORA_BW_500 /* KHz */
#define LORA_SPREADING_FACTOR LORA_SF9
#define LORA_CODINGRATE LORA_CR_4_5
#define LORA_PREAMBLE_LENGTH 8 /* Same for Tx and Rx */
#define LORA_SYMBOL_TIMEOUT 5 /* Symbols */
#define LORA_RX_TIMEOUT 10000 /* milliseconds */
#define RADIO_RX_BUFFER_SIZE 10
#define ZERO_OFFSET 0
typedef enum {
RADIO_STATE_IDLE,
RADIO_STATE_RX_COMPLETE,
RADIO_STATE_RX_ERROR
} RADIO_STATES;
PacketParams_t Radio_PacketParams;
const RadioLoRaBandwidths_t Radio_Bandwidths[] = { LORA_BW_125, LORA_BW_250, LORA_BW_500 };
RADIO_STATES Radio_State;
const char Radio_TimeoutText[] = "Rx Timeout\r\n";
const char Radio_ReceivedText[] = "Rx Received\r\n";
const char Radio_InitializedText[] = "Radio Initialized\r\n";
const char Radio_CrlfText[] = "\r\n";
extern UART_HandleTypeDef huart2;
void Radio_ReceiveMsg( void );
void Radio_IrqHandler(RadioIrqMasks_t radioIrq);
/*****************************************************************************************
* FUNCTION: Radio_Init
*
* DESCRIPTION: Initializes LoRa Radio
*
* PARAMETERS: None
*
* RETURN: None
*****************************************************************************************/
void Radio_Init(void)
{
ModulationParams_t modulationParams;
// Initialize the hardware (SPI bus, TCXO control, RF switch)
SUBGRF_Init(Radio_IrqHandler);
// Use DCDC converter if `DCDC_ENABLE` is defined in radio_conf.h
// "By default, the SMPS clock detection is disabled and must be enabled before enabling the SMPS." (6.1 in RM0453)
SUBGRF_WriteRegister(SUBGHZ_SMPSC0R, (SUBGRF_ReadRegister(SUBGHZ_SMPSC0R) | SMPS_CLK_DET_ENABLE));
SUBGRF_SetRegulatorMode();
// Use the whole 256-byte buffer for both TX and RX
SUBGRF_SetBufferBaseAddress(0x00, 0x00);
SUBGRF_SetRfFrequency(RF_FREQUENCY);
SUBGRF_SetRfTxPower(TX_OUTPUT_POWER);
SUBGRF_SetStopRxTimerOnPreambleDetect(FALSE);
SUBGRF_SetPacketType(PACKET_TYPE_LORA);
SUBGRF_WriteRegister( REG_LR_SYNCWORD, ( LORA_MAC_PRIVATE_SYNCWORD >> 8 ) & 0xFF );
SUBGRF_WriteRegister( REG_LR_SYNCWORD + 1, LORA_MAC_PRIVATE_SYNCWORD & 0xFF );
modulationParams.PacketType = PACKET_TYPE_LORA;
modulationParams.Params.LoRa.Bandwidth = LORA_BANDWIDTH;
modulationParams.Params.LoRa.CodingRate = LORA_CODINGRATE;
modulationParams.Params.LoRa.LowDatarateOptimize = 0x00;
modulationParams.Params.LoRa.SpreadingFactor = LORA_SPREADING_FACTOR;
SUBGRF_SetModulationParams(&modulationParams);
Radio_PacketParams.PacketType = PACKET_TYPE_LORA;
Radio_PacketParams.Params.LoRa.CrcMode = LORA_CRC_ON;
Radio_PacketParams.Params.LoRa.HeaderType = LORA_PACKET_VARIABLE_LENGTH;
Radio_PacketParams.Params.LoRa.InvertIQ = LORA_IQ_NORMAL;
Radio_PacketParams.Params.LoRa.PayloadLength = 0xFF;
Radio_PacketParams.Params.LoRa.PreambleLength = LORA_PREAMBLE_LENGTH;
SUBGRF_SetPacketParams(&Radio_PacketParams);
//SUBGRF_SetLoRaSymbNumTimeout(LORA_SYMBOL_TIMEOUT);
// WORKAROUND - Optimizing the Inverted IQ Operation, see DS_SX1261-2_V1.2 datasheet chapter 15.4
// RegIqPolaritySetup @address 0x0736
SUBGRF_WriteRegister( 0x0736, SUBGRF_ReadRegister( 0x0736 ) | ( 1 << 2 ) );
HAL_UART_Transmit(&huart2, (uint8_t *)Radio_InitializedText, sizeof(Radio_InitializedText) - 1, HAL_MAX_DELAY);
BSP_LED_On(LED_GREEN);
Radio_State = RADIO_STATE_IDLE;
Radio_ReceiveMsg();
}
/*****************************************************************************************
* FUNCTION: Radio_IrqHandler
*
* DESCRIPTION: Process a radio interrupt
*
* PARAMETERS: radioIrq - Event causing the interrupt
*
* RETURN: None
*****************************************************************************************/
void Radio_IrqHandler(RadioIrqMasks_t radioIrq)
{
switch (radioIrq)
{
case IRQ_TX_DONE:
break;
case IRQ_RX_DONE:
Radio_State = RADIO_STATE_RX_COMPLETE;
break;
case IRQ_RX_TX_TIMEOUT:
Radio_State = RADIO_STATE_RX_ERROR;
break;
case IRQ_CRC_ERROR:
Radio_State = RADIO_STATE_RX_ERROR;
break;
default:
Radio_State = RADIO_STATE_IDLE;
break;
}
}
/*****************************************************************************************
* FUNCTION: Radio_HandleTick
*
* DESCRIPTION: Process a Lora radio interrupt
*
* PARAMETERS: radioIrq - Event causing the interrupt
*
* RETURN: None
*****************************************************************************************/
void Radio_HandleTick(void)
{
char RxBuffer[RADIO_RX_BUFFER_SIZE];
if(Radio_State != RADIO_STATE_IDLE)
{
if(Radio_State == RADIO_STATE_RX_COMPLETE)
{
memset(RxBuffer, 0 , sizeof(RxBuffer));
SUBGRF_ReadBuffer( ZERO_OFFSET, (uint8_t *)RxBuffer, RADIO_RX_BUFFER_SIZE );
strcat(RxBuffer, Radio_CrlfText);
HAL_UART_Transmit(&huart2, (uint8_t *)RxBuffer, RADIO_RX_BUFFER_SIZE, HAL_MAX_DELAY);
BSP_LED_On(LED_RED);
HAL_Delay(500);
BSP_LED_Off(LED_RED);
}
else if(Radio_State == RADIO_STATE_RX_ERROR)
{
HAL_UART_Transmit(&huart2, (uint8_t *)Radio_TimeoutText, sizeof(Radio_TimeoutText) - 1, HAL_MAX_DELAY);
}
Radio_ReceiveMsg();
Radio_State = RADIO_STATE_IDLE;
}
}
/*****************************************************************************************
* FUNCTION: Radio_ReceiveMsg
*
* DESCRIPTION: Receive a message from the Roam Remote
*
* PARAMETERS: None
*
* RETURN: None
*****************************************************************************************/
void Radio_ReceiveMsg( void )
{
SUBGRF_SetDioIrqParams( IRQ_RX_DONE | IRQ_RX_TX_TIMEOUT | IRQ_CRC_ERROR | IRQ_HEADER_ERROR,
IRQ_RX_DONE | IRQ_RX_TX_TIMEOUT | IRQ_CRC_ERROR | IRQ_HEADER_ERROR,
IRQ_RADIO_NONE,
IRQ_RADIO_NONE );
SUBGRF_SetSwitch(RFO_LP, RFSWITCH_RX);
Radio_PacketParams.Params.LoRa.PayloadLength = 0xFF;
SUBGRF_SetPacketParams(&Radio_PacketParams);
SUBGRF_SetRx(LORA_RX_TIMEOUT << 6);
}
Solved! Go to Solution.
2023-12-13 07:03 AM
I found the issue.in the function Radio_SendMsg the lines
// Workaround 5.1 in DS.SX1261-2.W.APP (before each packet transmission)
SUBGRF_WriteRegister(0x0889, (SUBGRF_ReadRegister(0x0889) | 0x04));
Are only applicable for bandwidths less then 500kHz, for 500kHz bandwidth, the bit should be left as a zero. I removed these line from my code and now it works.
2023-12-06 10:38 AM - edited 2023-12-06 10:42 AM
You don't show the Tx side, but going to need
void SUBGRF_SetTx( uint32_t timeout );
Probably going to want continuous reception so the Rx side doesn't die mid transaction.
2023-12-06 01:48 PM
Thanks for the reply TeslaDelorean Here is the Tx code. Does this look OK?
I am not using SUBGRF_SetTx. Can you recommend a value for the timeout?
#include <stdio.h>
#include <radio_driver.h>
#include "types.h"
#include "radio.h"
#define RF_FREQUENCY 924000000 /* Hz */
#define TX_OUTPUT_POWER 14 /* dBm */
#define LORA_BANDWIDTH LORA_BW_500 /* KHz */
#define LORA_SPREADING_FACTOR LORA_SF9
#define LORA_CODINGRATE LORA_CR_4_5
#define LORA_PREAMBLE_LENGTH 8 /* Same for Tx and Rx */
#define LORA_SYMBOL_TIMEOUT 5 /* Symbols */
#define LORA_RX_TIMEOUT 10000 /* milliseconds */
#define RADIO_RX_BUFFER_SIZE 10
#define ZERO_OFFSET 0
typedef enum {
RADIO_STATE_IDLE,
RADIO_STATE_TX_COMPLETE,
RADIO_STATE_TX_ERROR
} RADIO_STATES;
PacketParams_t Radio_PacketParams;
const RadioLoRaBandwidths_t Radio_Bandwidths[] = { LORA_BW_125, LORA_BW_250, LORA_BW_500 };
RADIO_STATES Radio_State;
const char Radio_ErrorText[] = "Tx Error\r\n";
const char Radio_TxCompleteText[] = "Tx Complete\r\n";
const char Radio_InitializedText[] = "Radio Initialized\r\n";
const char Radio_PingMsg[] = "Ping";
extern UART_HandleTypeDef huart2;
void Radio_SendMsg( UINT8 *Msg, UINT8 MsgLen );
void Radio_IrqHandler(RadioIrqMasks_t radioIrq);
/*****************************************************************************************
* FUNCTION: Radio_Init
*
* DESCRIPTION: Open UDP socket to simulate messages to the ICC2 simulator
*
* PARAMETERS: None
*
* RETURN: None
*****************************************************************************************/
void Radio_Init(void)
{
ModulationParams_t modulationParams;
// Initialize the hardware (SPI bus, TCXO control, RF switch)
SUBGRF_Init(Radio_IrqHandler);
// Use DCDC converter if `DCDC_ENABLE` is defined in radio_conf.h
// "By default, the SMPS clock detection is disabled and must be enabled before enabling the SMPS." (6.1 in RM0453)
SUBGRF_WriteRegister(SUBGHZ_SMPSC0R, (SUBGRF_ReadRegister(SUBGHZ_SMPSC0R) | SMPS_CLK_DET_ENABLE));
SUBGRF_SetRegulatorMode();
// Use the whole 256-byte buffer for both TX and RX
SUBGRF_SetBufferBaseAddress(0x00, 0x00);
SUBGRF_SetRfFrequency(RF_FREQUENCY);
SUBGRF_SetRfTxPower(TX_OUTPUT_POWER);
SUBGRF_SetStopRxTimerOnPreambleDetect(FALSE);
SUBGRF_SetPacketType(PACKET_TYPE_LORA);
SUBGRF_WriteRegister( REG_LR_SYNCWORD, ( LORA_MAC_PRIVATE_SYNCWORD >> 8 ) & 0xFF );
SUBGRF_WriteRegister( REG_LR_SYNCWORD + 1, LORA_MAC_PRIVATE_SYNCWORD & 0xFF );
modulationParams.PacketType = PACKET_TYPE_LORA;
modulationParams.Params.LoRa.Bandwidth = LORA_BANDWIDTH;
modulationParams.Params.LoRa.CodingRate = LORA_CODINGRATE;
modulationParams.Params.LoRa.LowDatarateOptimize = 0x00;
modulationParams.Params.LoRa.SpreadingFactor = LORA_SPREADING_FACTOR;
SUBGRF_SetModulationParams(&modulationParams);
Radio_PacketParams.PacketType = PACKET_TYPE_LORA;
Radio_PacketParams.Params.LoRa.CrcMode = LORA_CRC_ON;
Radio_PacketParams.Params.LoRa.HeaderType = LORA_PACKET_VARIABLE_LENGTH;
Radio_PacketParams.Params.LoRa.InvertIQ = LORA_IQ_NORMAL;
Radio_PacketParams.Params.LoRa.PayloadLength = 0xFF;
Radio_PacketParams.Params.LoRa.PreambleLength = LORA_PREAMBLE_LENGTH;
SUBGRF_SetPacketParams(&Radio_PacketParams);
//SUBGRF_SetLoRaSymbNumTimeout(LORA_SYMBOL_TIMEOUT);
// WORKAROUND - Optimizing the Inverted IQ Operation, see DS_SX1261-2_V1.2 datasheet chapter 15.4
// RegIqPolaritySetup @address 0x0736
SUBGRF_WriteRegister( 0x0736, SUBGRF_ReadRegister( 0x0736 ) | ( 1 << 2 ) );
HAL_UART_Transmit(&huart2, (uint8_t *)Radio_InitializedText, sizeof(Radio_InitializedText) - 1, HAL_MAX_DELAY);
BSP_LED_On(LED_GREEN);
Radio_State = RADIO_STATE_IDLE;
Radio_SendMsg( (UINT8 *)Radio_PingMsg, sizeof(Radio_PingMsg) - 1 );
}
/*****************************************************************************************
* FUNCTION: Radio_IrqHandler
*
* DESCRIPTION: Process a radio interrupt
*
* PARAMETERS: radioIrq - Event causing the interrupt
*
* RETURN: None
*****************************************************************************************/
void Radio_IrqHandler(RadioIrqMasks_t radioIrq)
{
switch (radioIrq)
{
case IRQ_TX_DONE:
Radio_State = RADIO_STATE_TX_COMPLETE;
break;
case IRQ_RX_DONE:
break;
case IRQ_RX_TX_TIMEOUT:
Radio_State = RADIO_STATE_TX_ERROR;
break;
case IRQ_CRC_ERROR:
break;
default:
Radio_State = RADIO_STATE_IDLE;
break;
}
}
/*****************************************************************************************
* FUNCTION: Radio_HandleTick
*
* DESCRIPTION: Process a Lora radio interrupt
*
* PARAMETERS: radioIrq - Event causing the interrupt
*
* RETURN: None
*****************************************************************************************/
void Radio_HandleTick(void)
{
if(Radio_State != RADIO_STATE_IDLE)
{
if(Radio_State == RADIO_STATE_TX_COMPLETE)
{
HAL_UART_Transmit(&huart2, (uint8_t *)Radio_TxCompleteText, sizeof(Radio_TxCompleteText) - 1, HAL_MAX_DELAY);
HAL_Delay(10000);
BSP_LED_On(LED_RED);
HAL_Delay(500);
Radio_SendMsg( (UINT8 *)Radio_PingMsg, sizeof(Radio_PingMsg) - 1 );
BSP_LED_Off(LED_RED);
}
else if(Radio_State == RADIO_STATE_TX_ERROR)
{
HAL_UART_Transmit(&huart2, (uint8_t *)Radio_ErrorText, sizeof(Radio_ErrorText) - 1, HAL_MAX_DELAY);
}
Radio_State = RADIO_STATE_IDLE;
}
}
/*****************************************************************************************
* FUNCTION: Radio_ReceiveMsg
*
* DESCRIPTION: Receive a message from the Roam Remote
*
* PARAMETERS: None
*
* RETURN: None
*****************************************************************************************/
void Radio_SendMsg( UINT8 *Msg, UINT8 MsgLen )
{
SUBGRF_SetDioIrqParams( IRQ_TX_DONE | IRQ_RX_TX_TIMEOUT,
IRQ_TX_DONE | IRQ_RX_TX_TIMEOUT,
IRQ_RADIO_NONE,
IRQ_RADIO_NONE );
SUBGRF_SetSwitch(RFO_LP, RFSWITCH_TX);
// Workaround 5.1 in DS.SX1261-2.W.APP (before each packet transmission)
SUBGRF_WriteRegister(0x0889, (SUBGRF_ReadRegister(0x0889) | 0x04));
Radio_PacketParams.Params.LoRa.PayloadLength = MsgLen;
SUBGRF_SetPacketParams(&Radio_PacketParams);
SUBGRF_SendPayload((uint8_t *)Msg, MsgLen, 0);
}
2023-12-06 02:20 PM
SUBGRF_SetTx(11000); // 10s + 10% margin
I haven't built with this version but the older library with a slow SF12 beacon, would timeout with ST / SEMTECH examples.
Are you getting a TX_TIMEOUT error?
Do you idle the SUBGRF_SetSwitch() at some point?
2023-12-07 06:38 AM
Hello JMala.3
Your post has been reassigned to the online support team for more assistance.
Kind Regards
Joe WILLIAMS
STMicro Support
2023-12-07 06:51 AM
Please come back when you have an answer, dark-webbing this stuff in internal systems has significantly less reach.
2023-12-13 07:03 AM
I found the issue.in the function Radio_SendMsg the lines
// Workaround 5.1 in DS.SX1261-2.W.APP (before each packet transmission)
SUBGRF_WriteRegister(0x0889, (SUBGRF_ReadRegister(0x0889) | 0x04));
Are only applicable for bandwidths less then 500kHz, for 500kHz bandwidth, the bit should be left as a zero. I removed these line from my code and now it works.