O STM32 e módulo LoRaWAN da Radioenge são uma bela junção para aplicações de baixo consumo de energia e longo alcance, tanto é que o próprio módulo tem um STM32L presente.
Este projeto foi inteiramente construído dentro da STM32CubeIDE como uma forma de estudo e exemplo, então seu funcionamento é um pouco diferente do funcionamento no Arduino IDE. De qualquer forma a infraestrutura está o mais parecido possível com a biblioteca para Arduino.
Neste projeto utilizou um STM32 Núcleo 32 que tem a disposição de pinos equivalente ao Arduino Nano, porém o chip da placa usada neste teste foi um STM32L412KB. A biblioteca deverá funcionar com qualquer outro microcontrolador STM32, porém o chip e o projeto na IDE deve ser configurados da forma correta para que funcionem.
Configurando IDE e STM32 para se comunicar via serial
Antes de mais nada, é necessário primeiramente configurar o chip STM32 para realizar a comunicação serial com o módulo LoRaWAN. Para isso vamos inicialmente definir qual USART vamos utilizar, para o STM32L412KB será a USART1.
Após ter definido qual porta serial usar, basta apenas configurar para que atenda a necessidade dessa comunicação, para fazermos a configuração do chip de forma gráfica basta ir no arquivo .ioc e logo de cara vai aparecer uma imagem do chip com varias definições de GPIO.
No canto esquerdo da tela teremos um setor de configuração com vários termos o que vamos mexer é na conectividade, então clique nele e em seguida irá expandir varias conectividades possíveis.

Agora é só clicar no UART1, caso seu chip seja diferente desse do exemplo, basta simplesmente colocar uma UART disponível para o chip que você estiver usando. Em seguida clique na UART desejada e configure dessa mesma forma que da imagem a baixo:

Por fim, para concluirmos essa etapa da USART só será necessário habilitar para que possamos transmitir e receber pacotes sem problemas, para isso basta ir em project manager e habilitar a USART.

Adicionando biblioteca no STM32Cube IDE
Para adicionarmos uma biblioteca no STM32Cube IDE basta pegarmos os arquivos .h e .c e adicionarmos nas respectivas pastas a baixo:

É possível fazer um processo similar porém usando outra pasta, mas vamos focar no mais simples por enquanto. Além disso precisamos certificar que os arquivos adicionados não estão em modo de exclusão durante o build, para isso basta clicar com o botão direito sobre os arquivos e ir em: propriedades -> C/C++ Build.

Agora só falta mais uma coisinha para de fato finalizarmos a configuração, pois mesmo que você use uma núcleo 32 o chip pode ser diferente do que foi usado aqui. Por isso é necessário saber qual arquivo HAL chamar para o seu STM32. Para isso basta seguir o passo a passo a seguir:
- Acesse o arquivo main.c;
- Adicione um include “LoRaWAN_Radioenge.h”;
- Pressione o ctrl e clique sobre o arquivo main.h;
- Desça um pouco a página e copie o include similar a esse: “stm32l4xx_hal.h”;
- Acesse o arquivo “LoRaWAN_Radioenge.h” e cole o include copiado.
STM32 e módulo LoRaWAN da Radioenge
Agora só basta testar se o STM32 vai se comunicar de forma adequada com o módulo LoRaWAN da Radioenge, porém para que haja um teste completo é necessário que sua região tenha cobertura LoRaWAN para o teste.
Como já foi dito, o funcionamento da biblioteca está bem similar ao funcionamento da biblioteca para Arduino, então os parâmetros de conexão com a rede aparecerão e assim você poderá cadastrar o módulo na rede LoRaWAN.
Diagrama Núcleo 64 e LoRaWAN
O bom que caso você utilize as placas núcleo 32 é que independente se o chip é diferente, ainda assim a disposição dos pinos são as mesmas, isso ocorre pelo simples fato que as placas núcleo 32 tem a mesma pinagem que o Arduino nano, porém a frente dele é aonde tem botão de reset.
Porém ainda assim possa ser que seja bem mais fácil você acabar adquirindo um núcleo 64, até recomendo por ter mais portas e ter mais espaço na placa. De qualquer forma, independente da placa que você venha a usar vai funcionar.

- Módulo LoRaWAN Radioenge: Mercado Livre / Amazon;
- STM32: Aliexpress.
Código STM32 e LoRaWAN
Aqui devemos ter um pouco de atenção, pois a estrutura do STM32CubeIDE deve ser respeitada para que não haja dor de cabeça. Todo o código no arquivo main.c é gerenciado por comentários de inicio e fim, isso é uma forma de delimitar o que é do usuário e o que é da IDE, dessa forma a IDE identifica onde pode ou não mexer durante o processo de código gerado automaticamente.
Caso você não siga essa regra todo código que for feito e submetido por alguma configuração por meio de processo gráfico ou algo do tipo será jogado fora a cada passagem do gerador.
Você pode usar a estrutura do código abaixo para se basear e montar o seu código em main.c, possa ser que se copiar e colar funcione, mas não é garantido, por isso volto a repetir que foque na estrutura e replique isso.
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.c
* @brief : Main program body
******************************************************************************
* @attention
*
* Copyright (c) 2023 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"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "main.h"
#include "LoRaWAN_Radioenge.h"
/* 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 ---------------------------------------------------------*/
UART_HandleTypeDef huart1;
UART_HandleTypeDef huart2;
/* USER CODE BEGIN PV */
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_USART2_UART_Init(void);
static void MX_USART1_UART_Init(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_USART2_UART_Init();
MX_USART1_UART_Init();
/* USER CODE BEGIN 2 */
LoRaWAN_Begin(1, &huart1, &huart2);
pinMode(2, OUTPUT);
JOIN();
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
SendString("elcereza.com", 1);
for(uint8_t i = 0; i < 4; ++i){
digitalWrite(2, 1);
HAL_Delay(100);
HAL_GPIO_TogglePin(LD3_GPIO_Port, LD3_Pin);
digitalWrite(2, 0);
HAL_Delay(100);
}
/* 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 the main internal regulator output voltage
*/
if (HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1) != HAL_OK)
{
Error_Handler();
}
/** Configure LSE Drive Capability
*/
HAL_PWR_EnableBkUpAccess();
__HAL_RCC_LSEDRIVE_CONFIG(RCC_LSEDRIVE_LOW);
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSE|RCC_OSCILLATORTYPE_MSI;
RCC_OscInitStruct.LSEState = RCC_LSE_ON;
RCC_OscInitStruct.MSIState = RCC_MSI_ON;
RCC_OscInitStruct.MSICalibrationValue = 0;
RCC_OscInitStruct.MSIClockRange = RCC_MSIRANGE_10;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = 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;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1) != HAL_OK)
{
Error_Handler();
}
/** Enable MSI Auto calibration
*/
HAL_RCCEx_EnableMSIPLLMode();
}
/**
* @brief USART1 Initialization Function
* @param None
* @retval None
*/
static void MX_USART1_UART_Init(void)
{
/* USER CODE BEGIN USART1_Init 0 */
/* USER CODE END USART1_Init 0 */
/* USER CODE BEGIN USART1_Init 1 */
/* USER CODE END USART1_Init 1 */
huart1.Instance = USART1;
huart1.Init.BaudRate = 9600;
huart1.Init.WordLength = UART_WORDLENGTH_8B;
huart1.Init.StopBits = UART_STOPBITS_1;
huart1.Init.Parity = UART_PARITY_NONE;
huart1.Init.Mode = UART_MODE_TX_RX;
huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart1.Init.OverSampling = UART_OVERSAMPLING_16;
huart1.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
huart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
if (HAL_UART_Init(&huart1) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN USART1_Init 2 */
/* USER CODE END USART1_Init 2 */
}
/**
* @brief USART2 Initialization Function
* @param None
* @retval None
*/
static void MX_USART2_UART_Init(void)
{
/* USER CODE BEGIN USART2_Init 0 */
/* USER CODE END USART2_Init 0 */
/* USER CODE BEGIN USART2_Init 1 */
/* USER CODE END USART2_Init 1 */
huart2.Instance = USART2;
huart2.Init.BaudRate = 115200;
huart2.Init.WordLength = UART_WORDLENGTH_8B;
huart2.Init.StopBits = UART_STOPBITS_1;
huart2.Init.Parity = UART_PARITY_NONE;
huart2.Init.Mode = UART_MODE_TX_RX;
huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart2.Init.OverSampling = UART_OVERSAMPLING_16;
huart2.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
huart2.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
if (HAL_UART_Init(&huart2) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN USART2_Init 2 */
/* USER CODE END USART2_Init 2 */
}
/**
* @brief GPIO Initialization Function
* @param None
* @retval None
*/
static void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* USER CODE BEGIN MX_GPIO_Init_1 */
/* USER CODE END MX_GPIO_Init_1 */
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(LD3_GPIO_Port, LD3_Pin, GPIO_PIN_RESET);
/*Configure GPIO pin : LD3_Pin */
GPIO_InitStruct.Pin = LD3_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(LD3_GPIO_Port, &GPIO_InitStruct);
/* USER CODE BEGIN MX_GPIO_Init_2 */
/* USER CODE END MX_GPIO_Init_2 */
}
/* 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 */
Funcionamento do STM32 e LoRaWAN da Radioenge
No vídeo abaixo é possível ver o debug da comunicação do STM32 com o módulo LoRaWAN da Radioenge através do programa Putty onde informa os parâmetros de conexão LoRaWAN, envia uma string via rádio e ainda fica mudando o estado lógico da GPIO2 do módulo.
No canto inferior esquerdo é possível ver a comunicação de rádio do protocolo LoRaWAN e na direita temos um gateway LoRaWAN da Radioenge conectado na TTN recebendo a string enviada pelo o módulo com o STM32.
