RAK3172 P2P with STM32CubeIDE

I’ve follow RAK3172_STM32CubeWL_SDK_1_3 and RAK3172 Wiki then I create my own project and I can compile and upload without error.
But I have no idea how to set it to RX mode? I’ve play with the PingPong app, but it to complicated for me. I just want it be RX Mode and get interrupt whenever LoRa package has arrived. Thank for advance.
This is my main.c code.

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2024 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "dma.h"
#include "app_subghz_phy.h"
#include "gpio.h"
#include "sys_app.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */

/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */

/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_DMA_Init();
  MX_SubGHz_Phy_Init();
  /* USER CODE BEGIN 2 */
  HAL_GPIO_WritePin(GPIOB, LED1_Pin, SET);
  HAL_Delay(500);
  HAL_GPIO_WritePin(GPIOB, LED1_Pin, RESET);
  APP_LOG(TS_OFF, VLEVEL_L, "\n\rLoRa P2P Starting...\n\r");
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */
    MX_SubGHz_Phy_Process();
    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Configure LSE Drive Capability
  */
  HAL_PWR_EnableBkUpAccess();
  __HAL_RCC_LSEDRIVE_CONFIG(RCC_LSEDRIVE_LOW);

  /** Configure the main internal regulator output voltage
  */
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);

  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSE|RCC_OSCILLATORTYPE_MSI;
  RCC_OscInitStruct.LSEState = RCC_LSE_ON;
  RCC_OscInitStruct.MSIState = RCC_MSI_ON;
  RCC_OscInitStruct.MSICalibrationValue = RCC_MSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.MSIClockRange = RCC_MSIRANGE_11;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

  /** Configure the SYSCLKSource, HCLK, PCLK1 and PCLK2 clocks dividers
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK3|RCC_CLOCKTYPE_HCLK
                              |RCC_CLOCKTYPE_SYSCLK|RCC_CLOCKTYPE_PCLK1
                              |RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_MSI;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
  RCC_ClkInitStruct.AHBCLK3Divider = RCC_SYSCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
  {
    Error_Handler();
  }
}

/* USER CODE BEGIN 4 */

/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
  __disable_irq();
  while (1)
  {
  }
  /* USER CODE END Error_Handler_Debug */
}

#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 CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

Hi @anusornint ,

We do not really support low level STM32WL codes here as they are made and maintained by ST.

However, on the PingPong example, you can probably try to tweak it and enable only RX mode.

Somewhere in this section:

Thank for reply, I know you don’t support low level STM32WL codes and I know you support only RUI3, but I’ve some issues with it. I’ve posted on ST, but they don’t support for RAK3172 too. I’m trying to start with the PingPong example, but too difficult for newbie like me. Especially with regenerate code for RAK3172. I can do it, but I don’t understand it so I can’t adapt to my project. Anyway, I will be very grateful if you show me very simplest TX and RX code separated.

This requirement can be easily done via RUI3. I am not sure why you do not want to use it.

With regards to Pingping example, it uses the subghz_phy_app to create the abstraction regardless of the RF protocol (LoRa or FSK). I already directed you on that part of the code. But to be honest, even myself is lost on how to modify ST examples plus the added layer of CubeMX. If you think about it, that is exactly the reason why there is RUI3. If you really want to push this endeavor, you can ask again ST support and give you example not for RUI3 but for the STM32WL Eval Board, any info about that would be a big help for you.

Thank for reply. I have 30 of RAK3172 modules, and I’ve done RX Mode with RUI3, but all of them not stable, some time they not respons (some time 3-4 minutes, some time 1 day). I don’t know why, so I try to use native IDE just for test.
Could you show me simplest of “RX Mode and get interrupt whenever LoRa package” with RUI3, I’ll try come back to RUI3 again.

“some time they not respons (some time 3-4 minutes, some time 1 day)”

What does it mean exactly?

What are you doing in your code? If you are using the RUI3 P2P RX callback to do lengthy calculations or even try to send a P2P packet, it will not work. The time spend in these callbacks should be as short as possible.

I wrote a simple P2P example. RX device waits for a packet to arrive, then it responds to that received packet by sending it’s own packet. Finished and published the code today, but still testing. LoRa_P2P

Thank for your code. I’m sorry for my English. I mean it randomly not responding. sometime runing for 3-4 minutes then not responding and somtime runing for 1-2 days then not responding.

My TX side use AT Command for sending JSON fomat string.

This is my RX code:

/*************************************
 * This example is from https://github.com/Kongduino/RUI3_LoRa_P2P_PING_PONG
 * This example needs two devices, a device will send LoRa P2P package after receiving LoRa P2P package.
 *************************************/
long startTime;
bool rx_done = false;
double myFreq = 923000000;
uint16_t sf = 12, bw = 0, cr = 0, preamble = 8, txPower = 22;
#define RX_LED PA10

unsigned long previousMillis = 0;
const long interval = 1000;
int rx_ledState = LOW;
int tx_ledState = LOW;
unsigned long startMillis = 0;
unsigned long stopMillis = 0;

#include <ArduinoJson.h>
int z;
long int d;
bool c;

void hexDump(uint8_t * buf, uint16_t len)
{
    char alphabet[17] = "0123456789abcdef";
    Serial.print(F("   +------------------------------------------------+ +----------------+\r\n"));
    Serial.print(F("   |.0 .1 .2 .3 .4 .5 .6 .7 .8 .9 .a .b .c .d .e .f | |      ASCII     |\r\n"));
    for (uint16_t i = 0; i < len; i += 16) {
        if (i % 128 == 0)
            Serial.print(F("   +------------------------------------------------+ +----------------+\r\n"));
        char s[] = "|                                                | |                |\r\n";
        uint8_t ix = 1, iy = 52;
        for (uint8_t j = 0; j < 16; j++) {
            if (i + j < len) {
  	            uint8_t c = buf[i + j];
  	            s[ix++] = alphabet[(c >> 4) & 0x0F];
  	            s[ix++] = alphabet[c & 0x0F];
  	            ix++;
  	            if (c > 31 && c < 128)
  	                s[iy++] = c;
  	            else
  	                s[iy++] = '.';
            }
        }
        uint8_t index = i / 16;
        if (i < 256)
            Serial.write(' ');
        Serial.print(index, HEX);
        Serial.write('.');
        Serial.print(s);
    }
    Serial.print(F("   +------------------------------------------------+ +----------------+\r\n"));
}

void recv_cb(rui_lora_p2p_recv_t data)
{
    digitalWrite(RX_LED, HIGH);  // Turn-on RX_LED
    rx_done = true;
    if (data.BufferSize == 0) {
        Serial.println("Empty buffer.");
        return;
        digitalWrite(RX_LED, LOW);  // Turn-off RX_LED
    }

  // Json part
  static StaticJsonDocument<200> doc;
  int packetSize = data.BufferSize;
  if(packetSize){
    Serial.printf("Recieve packet: %d Bytes\r\n",packetSize);
  }

  // parse the JSON string in the buffer
  DeserializationError error = deserializeJson(doc, data.Buffer);    
  if(error){
    Serial.printf("deserializeJson() failed: %s\r\n", error.f_str());
  } else {
    // add RSSI to the JSON document
    doc["r"] = data.Rssi;
    // serialize the JSON document into a string
    String jsonString;
    serializeJson(doc, jsonString);
    // print the JSON string
    Serial.println(jsonString);

    // get the value of the "message" key
    const char* message = doc["r"];
    z = int(doc["z"]);
    c = int(doc["c"]);
    d = int(doc["d"])*1000;
 
    Serial.printf("Data Recieved => Zone: %d\t cmd: %s\t dur: %d\r\n", z, c ? "ON": "OFF", d);
  }

    digitalWrite(RX_LED, LOW);  // Turn-off RX_LED
}

void send_cb(void)
{
    // Not use
    Serial.printf("P2P set Rx mode %s\r\n",
		api.lora.precv(65534) ? "Success" : "Fail");
}

void setup()
{
    pinMode(RX_LED, OUTPUT);
    digitalWrite(RX_LED, LOW);
    Serial.begin(115200);
    Serial.println("RAKwireless LoRaWan P2P Example");
    Serial.println("------------------------------------------------------");
    delay(2000);
    startTime = millis();
    
    if(api.lora.nwm.get() != 0)
    {
        Serial.printf("Set Node device work mode %s\r\n",
            api.lora.nwm.set() ? "Success" : "Fail");
        api.system.reboot();
    }

    Serial.println("P2P Start");
    Serial.printf("Hardware ID: %s\r\n", api.system.chipId.get().c_str());
    Serial.printf("Model ID: %s\r\n", api.system.modelId.get().c_str());
    Serial.printf("RUI API Version: %s\r\n",
  		api.system.apiVersion.get().c_str());
    Serial.printf("Firmware Version: %s\r\n",
  		api.system.firmwareVersion.get().c_str());
    Serial.printf("AT Command Version: %s\r\n",
  		api.system.cliVersion.get().c_str());
    Serial.printf("Set P2P mode frequency %3.3f: %s\r\n", (myFreq / 1e6),
  		api.lora.pfreq.set(myFreq) ? "Success" : "Fail");
    Serial.printf("Set P2P mode spreading factor %d: %s\r\n", sf,
  		api.lora.psf.set(sf) ? "Success" : "Fail");
    Serial.printf("Set P2P mode bandwidth %d: %s\r\n", bw,
  		api.lora.pbw.set(bw) ? "Success" : "Fail");
    Serial.printf("Set P2P mode code rate 4/%d: %s\r\n", (cr + 5),
  		api.lora.pcr.set(cr) ? "Success" : "Fail");
    Serial.printf("Set P2P mode preamble length %d: %s\r\n", preamble,
  		api.lora.ppl.set(preamble) ? "Success" : "Fail");
    Serial.printf("Set P2P mode tx power %d: %s\r\n", txPower,
  		api.lora.ptp.set(txPower) ? "Success" : "Fail");
    api.lora.registerPRecvCallback(recv_cb);
    api.lora.registerPSendCallback(send_cb);
    Serial.printf("P2P set Rx mode %s\r\n",
  		api.lora.precv(65534) ? "Success" : "Fail"); // Forever RX Mode
}

void loop()
{

}

I’ve tried without JSON, but still randomly not responding.
Anyhow, I’ll try with your new code.

Try to move the de-serialization of thew received data out of the RX callback.
These callbacks should not perform longer tasks.

I am working on another example that shows how to process received data outside of the RX callback. But it is still work in progress.

Some code snippets:
Globals:

volatile bool has_rx = false;
rui_lora_p2p_recv_t rx_data;
uint8_t rx_buffer[512];

RX callback:

void recv_cb(rui_lora_p2p_recv_t data)
{
	tx_active = false;

	has_rx = true;
	rx_data.Rssi = data.Rssi;
	rx_data.Snr = data.Snr;
	rx_data.Status = data.Status;
	rx_data.Buffer = rx_buffer;
	rx_data.BufferSize = data.BufferSize;
	memcpy(rx_buffer, data.Buffer, data.BufferSize);
}

RX data handler

void rx_handler(void)
{
	if (has_rx)
	{
		MYLOG("RX_HANDLER", "RX task started");
		has_rx = false;
		MYLOG("RX-P2P-CB", "P2P RX, RSSI %d, SNR %d", rx_data.Rssi, rx_data.Snr);

#if MY_DEBUG > 0
		for (int i = 0; i < rx_data.BufferSize; i++)
		{
			Serial.printf("%02X", rx_data.Buffer[i]);
		}
		Serial.print("\r\n");
#endif
	}

	MYLOG("RX_HANDLER", "RX task sleep");
	// Back to sleep
	delay(5000);
}

Setup:

void setup()
{
	// usual setup() stuff

	// Create a timer to handle the RX data. (checks every 5 seconds if data has arrived)
	api.system.timer.create(RAK_TIMER_0, rx_handler, RAK_TIMER_PERIODIC);
	if (custom_parameters.send_interval != 0)
	{
		// Start a timer.
		api.system.timer.start(RAK_TIMER_0, 5000, NULL);
	}
}

Loop:

void loop()
{
	api.system.sleep.all();
}

Thank you for your support. Now, I’ve got what did you want to tell me. I’ll do shortest RX callback as you show me.

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.