cancel
Showing results for 
Search instead for 
Did you mean: 

Using Spreading factor 12 on NUCLEO-WL55JC1 LoRa boards

JMala.3
Associate III

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

 

 

 

1 ACCEPTED SOLUTION

Accepted Solutions

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.

View solution in original post

6 REPLIES 6

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 Up vote any posts that you find helpful, it shows what's working..
JMala.3
Associate III

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

 

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 Up vote any posts that you find helpful, it shows what's working..
Joe WILLIAMS
ST Employee

Hello JMala.3

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

Kind Regards

Joe WILLIAMS

STMicro Support

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 Up vote any posts that you find helpful, it shows what's working..

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.