This code is an extension of Henri Heimann work for stm32L series and RFM95.
The following features have been added:
- Different SF (Receive windows adjusted accordingly)
- Adjustable transmitt power levels
- SF9 (or SF12) in receive window 2
- Receive window timings have been adjusted compared to the original library (wrong calculations in the original code)
- Process mac commands extended: now all the commands specified in the LoRaWAN Link Layer are supported
- Automtically repsonds to networks server requests
- Receive application data
- Added error detection mechanisms with 12 possible states to detect faulty behavior
- Initialize SPI in full duplex mode, 8 bits data size. Clock can be up to 10 MHz (5 MHz was used). pull-up resistors can be used for all MISO, MOSI and SCK pins. This is necessary to avoid parasitic currents while MCU works in STOP mode 2.
- Use a generic GPIO as CS for the SPI. Configure it in push pull with output level high. Enable internal pull-up to prevent RFM reactions during MCU initialization.
- Use another GPIO as RFM95 reset (active LOW). Connect an external weak pull-up (avoid currents in the case in which the RFM is connected to a different VDD > 3.3 V used by the MCU) and drive it with Open-drain configuration. Set GPIO output level HIGH (reset command triggered on a digital LOW).
- Enable 3 GPIO as EXTI, and configure them for "rising edge trigger detection". No pull up resistors are needed in this case. Enable also interrupt generation in the corresponding NVIC table.
- Enable LPTIM as "Counts internal clock events". In the clock configuration window, select LSE as clock source for the LPTIM section. Enable also the corresponding interrput in the NVIC table.
- In the "Security" window enable the RNG for random channel selection. Interrupts are not needed for this section. In the clock window select "PLLQ" as clock source for "CLK48 Clock Mux" and ensure the RNG clock is > 5 MHz (arange it around ~20 MHz). This is needed since the PLLP-PLLR-PLLQ section is automatically activated after recovering from STOP mode 2.
- In the automatic generated code, comment out "HAL_NVIC_SetPriority(EXTI15_10_IRQn, 0, 0) and HAL_NVIC_EnableIRQ(EXTI15_10_IRQn)" in "MX_GPIO_Init" function. Indeed the EXTI interrupt appears to cause an hard fault error at startup. The NVIC initialization for interrupt on DIO5 can be added after the "/* USER CODE BEGIN 2 */" statement (i.e. after initialization code has been executed).
- in your main.c file ensure to implement these functions get_precision_tick, precision_sleep_until, random_int and get_battery_level. One possible implementation is proposed in the "USER CODE BEGIN 4" section in my "main.c" file using LPTIM and RNG.
- Initialize the following variables in the define section:
rfm95_handle_t rfm95_handle = {0}; // This structure will be used to manage all the configurations for the RFM volatile uint32_t lptim_tick_msb = 0; // Track the LPTIM msb --> Remember to clear this variable beofre initializing the LPTIM uint32_t lse_clk = (1<<15); // defines the LSE clock speed (in Hz) uint16_t rfm95_status; // handle rfm95 status to process rfm outcomes - setup your RFM95 configurations:
// SET HARDWARE CONNECTIONS: rfm95_handle.spi_handle = &hspi2; rfm95_handle.nss_port = SPI_CS_GPIO_Port; rfm95_handle.nss_pin = SPI_CS_Pin; rfm95_handle.nrst_port = RFM95_nrst_GPIO_Port; rfm95_handle.nrst_pin = RFM95_nrst_Pin; // SET TX POWER, SF, RX2-SF: rfm95_handle.config.tx_sf = 7; rfm95_handle.config.tx_power = 14; rfm95_handle.config.rx2_sf = 9; // Set application data magic word: rfm95_handle.config.lora_magic = 0xABCD; // INIT FIELDS FOR RX MODE: rfm95_handle.precision_tick_frequency = lse_clk; rfm95_handle.precision_tick_drift_ns_per_s = 20000; rfm95_handle.receive_mode = RFM95_RECEIVE_MODE_RX12; rfm95_handle.get_precision_tick = get_precision_tick; rfm95_handle.precision_sleep_until = precision_sleep_until; rfm95_handle.random_int = random_int; rfm95_handle.get_battery_level = get_battery_level; // SETUP device address, network and application session keys: memcpy(rfm95_handle.device_address, dev_addr, sizeof(dev_addr)); memcpy(rfm95_handle.network_session_key, nw_session_keys, sizeof(nw_session_keys)); memcpy(rfm95_handle.application_session_key, app_session_keys, sizeof(app_session_keys));
Look at the "main.c" file for a complete working example.
- Semtech guide to LoRaWAN transmitt/receive/process mac commands...
- AN1200.24 from Semtech for setting up RFM95.