You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
384 lines
12 KiB
384 lines
12 KiB
/* 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 "i2c.h" |
|
#include "usart.h" |
|
#include "spi.h" |
|
#include "gpio.h" |
|
|
|
/* Private includes ----------------------------------------------------------*/ |
|
/* USER CODE BEGIN Includes */ |
|
#include "stdbool.h" |
|
#include "string.h" |
|
#include "stm32wlxx_LoRa_E5_mini.h" |
|
#include "radio_driver.h" |
|
#include "subghz.h" |
|
/* USER CODE END Includes */ |
|
|
|
/* Private typedef -----------------------------------------------------------*/ |
|
/* USER CODE BEGIN PTD */ |
|
#define MAX_LORA_PAYLOAD_LEN (255) |
|
#define PACKET_FLAGS_HOP_LIMIT_MASK (0x07) |
|
#define PACKET_FLAGS_WANT_ACK_MASK (0x08) |
|
#define PACKET_FLAGS_VIA_MQTT_MASK (0x10) |
|
#define PACKET_FLAGS_HOP_START_MASK (0xE0) |
|
#define PACKET_FLAGS_HOP_START_SHIFT (5) |
|
|
|
typedef struct packet_header_s{ |
|
uint32_t to, from; // can be 1 byte or four bytes |
|
|
|
uint32_t id; // can be 1 byte or 4 bytes |
|
|
|
/* Usage of flags: |
|
* |
|
* The bottom three bits of flags are use to store hop_limit when sent over the wire. */ |
|
uint8_t flags; |
|
|
|
/** The channel hash - used as a hint for the decoder to limit which channels we consider */ |
|
uint8_t channel; |
|
|
|
/* ***For future use*** Last byte of the NodeNum of the next-hop for this packet */ |
|
uint8_t next_hop; |
|
|
|
/* ***For future use*** Last byte of the NodeNum of the node that will relay/relayed this packet */ |
|
uint8_t relay_node; |
|
} packet_header_t; |
|
typedef struct packet_s { |
|
/* The header, as defined just before */ |
|
packet_header_t header; |
|
|
|
/* The payload, of maximum length minus the header, aligned just to be sure */ |
|
uint8_t payload[MAX_LORA_PAYLOAD_LEN + 1 - sizeof(packet_header_t)] __attribute__((__aligned__)); |
|
} packet_t; |
|
/* USER CODE END PTD */ |
|
|
|
/* Private define ------------------------------------------------------------*/ |
|
/* USER CODE BEGIN PD */ |
|
|
|
/* USER CODE END PD */ |
|
|
|
/* Private macro -------------------------------------------------------------*/ |
|
/* USER CODE BEGIN PM */ |
|
#define RF_FREQUENCY 906875000 /* Hz */ |
|
#define TX_OUTPUT_POWER 17 /* dBm */ |
|
#define LORA_BANDWIDTH LORA_BW_250 |
|
#define LORA_SPREADING_FACTOR LORA_SF11 |
|
#define LORA_CODINGRATE LORA_CR_4_5 |
|
#define LORA_PREAMBLE_LENGTH 16 /* Same for Tx and Rx */ |
|
#define LORA_SYMBOL_TIMEOUT 16 /* Symbols */ |
|
/* USER CODE END PM */ |
|
|
|
/* Private variables ---------------------------------------------------------*/ |
|
|
|
/* USER CODE BEGIN PV */ |
|
PacketParams_t packetParams; // TODO: this is lazy... |
|
/* USER CODE END PV */ |
|
|
|
/* Private function prototypes -----------------------------------------------*/ |
|
void SystemClock_Config(void); |
|
/* USER CODE BEGIN PFP */ |
|
void radio_init(); |
|
void radio_cb(RadioIrqMasks_t radioIrq); |
|
/* 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 */ |
|
packet_t pkt = { |
|
.header = { |
|
.to = 0x61077475, |
|
.from = 0xdeadbeef, |
|
.id = 0, |
|
.flags = (PACKET_FLAGS_HOP_START_MASK & (3 << PACKET_FLAGS_HOP_START_SHIFT)) | \ |
|
(PACKET_FLAGS_WANT_ACK_MASK) | \ |
|
(PACKET_FLAGS_HOP_LIMIT_MASK & 3), |
|
.channel = 0, |
|
.next_hop = 0, |
|
.relay_node = 0 |
|
}, |
|
.payload = "\x01Hello, world!" |
|
}; |
|
/* 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_USART1_UART_Init(); |
|
MX_I2C2_Init(); |
|
MX_LPUART1_UART_Init(); |
|
MX_USART2_UART_Init(); |
|
MX_SPI2_Init(); |
|
/* USER CODE BEGIN 2 */ |
|
radio_init(); |
|
do |
|
{ |
|
HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_SET); |
|
} while(hsubghz.State != HAL_SUBGHZ_STATE_READY); |
|
HAL_Delay(1000); |
|
SUBGRF_SetDioIrqParams( IRQ_TX_DONE | IRQ_RX_DONE | IRQ_PREAMBLE_DETECTED | IRQ_RX_TX_TIMEOUT, |
|
IRQ_TX_DONE | IRQ_RX_DONE | IRQ_PREAMBLE_DETECTED | IRQ_RX_TX_TIMEOUT, |
|
IRQ_RADIO_NONE, |
|
IRQ_RADIO_NONE ); |
|
|
|
SUBGRF_SetStandby(MODE_STDBY_RC); |
|
HAL_Delay(250); |
|
SUBGRF_SetSwitch(RFO_LP, RFSWITCH_RX); |
|
packetParams.Params.LoRa.PayloadLength = 0xff; |
|
SUBGRF_SetPacketParams(&packetParams); |
|
SUBGRF_SetRx(0x00fffffe); |
|
/* USER CODE END 2 */ |
|
|
|
/* Infinite loop */ |
|
/* USER CODE BEGIN WHILE */ |
|
while(1) |
|
{ |
|
/* 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)); |
|
packetParams.Params.LoRa.PayloadLength = sizeof(packet_header_t) + strlen((char *) pkt.payload); |
|
SUBGRF_SetPacketParams(&packetParams); |
|
pkt.header.id++; |
|
SUBGRF_SendPayload((uint8_t *) &pkt, sizeof(packet_header_t) + 13, 0); |
|
HAL_Delay(5000);*/ |
|
HAL_Delay(50); |
|
SUBGRF_SetRx(0x00fffffe); |
|
} |
|
/* USER CODE END WHILE */ |
|
|
|
/* 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 |
|
*/ |
|
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1); |
|
|
|
/** Initializes the CPU, AHB and APB buses clocks |
|
*/ |
|
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE; |
|
RCC_OscInitStruct.HSEState = RCC_HSE_BYPASS_PWR; |
|
RCC_OscInitStruct.HSEDiv = RCC_HSE_DIV2; |
|
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; |
|
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; |
|
RCC_OscInitStruct.PLL.PLLM = RCC_PLLM_DIV1; |
|
RCC_OscInitStruct.PLL.PLLN = 12; |
|
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2; |
|
RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV4; |
|
RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2; |
|
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) |
|
{ |
|
Error_Handler(); |
|
} |
|
|
|
/** Enable the HSE Prescaler |
|
*/ |
|
__HAL_RCC_HSE_DIV2_ENABLE(); |
|
|
|
/** 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_PLLCLK; |
|
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 */ |
|
/** |
|
* @brief Initialize the Sub-GHz radio and dependent hardware. |
|
* @retval None |
|
*/ |
|
void radio_init(void) |
|
{ |
|
uint16_t syncword = 0x24b4; |
|
ModulationParams_t mod_params = { |
|
.PacketType = PACKET_TYPE_LORA, |
|
.Params.LoRa = { |
|
.Bandwidth = LORA_BANDWIDTH, |
|
.CodingRate = LORA_CODINGRATE, |
|
.LowDatarateOptimize = 0x01, |
|
.SpreadingFactor = LORA_SPREADING_FACTOR |
|
} |
|
}; |
|
|
|
// Initialize the hardware (SPI bus, TCXO control, RF switch) |
|
SUBGRF_Init(radio_cb); |
|
|
|
// 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, ( syncword >> 8 ) & 0xFF ); |
|
SUBGRF_WriteRegister( REG_LR_SYNCWORD + 1, syncword & 0xFF ); |
|
|
|
SUBGRF_SetModulationParams(&mod_params); |
|
|
|
packetParams.PacketType = PACKET_TYPE_LORA; |
|
packetParams.Params.LoRa.CrcMode = LORA_CRC_ON; |
|
packetParams.Params.LoRa.HeaderType = LORA_PACKET_VARIABLE_LENGTH; |
|
packetParams.Params.LoRa.InvertIQ = LORA_IQ_NORMAL; |
|
packetParams.Params.LoRa.PayloadLength = 0xFF; |
|
packetParams.Params.LoRa.PreambleLength = LORA_PREAMBLE_LENGTH; |
|
SUBGRF_SetPacketParams(&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 ) ); |
|
} |
|
|
|
void radio_cb(RadioIrqMasks_t radio_irq) |
|
{ |
|
packet_t pkt; |
|
uint8_t size; |
|
|
|
if(radio_irq & IRQ_TX_DONE) |
|
{ |
|
HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin); |
|
} |
|
if(radio_irq & IRQ_RX_DONE) |
|
{ |
|
HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_SET); |
|
SUBGRF_GetPayload((uint8_t *) &pkt, &size, MAX_LORA_PAYLOAD_LEN); |
|
} |
|
if(radio_irq & IRQ_PREAMBLE_DETECTED) |
|
{ |
|
HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_RESET); |
|
} |
|
if(radio_irq & IRQ_SYNCWORD_VALID) |
|
{ |
|
HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin); |
|
} |
|
if(radio_irq & IRQ_HEADER_VALID) |
|
{ |
|
HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin); |
|
} |
|
if(radio_irq & IRQ_HEADER_ERROR) |
|
{ |
|
HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin); |
|
} |
|
if(radio_irq & IRQ_CRC_ERROR) |
|
{ |
|
HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin); |
|
} |
|
if(radio_irq & IRQ_CAD_CLEAR) |
|
{ |
|
HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin); |
|
} |
|
if(radio_irq & IRQ_CAD_DETECTED) |
|
{ |
|
HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin); |
|
} |
|
if(radio_irq & IRQ_RX_TX_TIMEOUT) |
|
{ |
|
/* */ |
|
} |
|
else |
|
{ |
|
/* */ |
|
} |
|
SUBGRF_ClearIrqStatus(radio_irq); |
|
} |
|
/* 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 */
|
|
|