Skip to main content
JMala.3
Associate III
December 6, 2023
Solved

Using Spreading factor 12 on NUCLEO-WL55JC1 LoRa boards

  • December 6, 2023
  • 6 replies
  • 3261 views

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);
}

 

 

 

This topic has been closed for replies.
Best answer by JMala.3

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.

6 replies

Tesla DeLorean
Guru
December 6, 2023

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.

 

Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
JMala.3
JMala.3Author
Associate III
December 6, 2023

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);
}

 

Tesla DeLorean
Guru
December 6, 2023

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?

Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
Joe WILLIAMS
ST Employee
December 7, 2023

Hello JMala.3

Your post has been reassigned to the online support team for more assistance.

Kind Regards

Joe WILLIAMS

STMicro Support

Tesla DeLorean
Guru
December 7, 2023

Please come back when you have an answer, dark-webbing this stuff in internal systems has significantly less reach.

Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
JMala.3
JMala.3AuthorBest answer
Associate III
December 13, 2023

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.