Giter Club home page Giter Club logo

stm32-hal-rfm95's Introduction

RFM95

STM32 HAL driver for RFM95 LoraWAN modules.

Software License: MIT

Usage

For CMake based projects (for example when using STM32CubeMX projects with CLion) you can for example setup the driver as submodule and link to it:

add_subdirectory("<directory-to-driver>/rfm95")
target_link_libraries(<target-name> stm32-hal-rfm95)

Getting Started

After connecting the RFM95 module to your microcontroller via SPI and initialising the bus using Cube you can use this library to interact with the RFM95 module as shown in the following example. You are required to handle DIO0, 1 and 5 interrupts:

int main() {
    // Create the handle for the RFM95 module.
    rfm95_handle_t rfm95_handle = {
        .spi_handle = &hspi1,
		.nss_port = RFM95_NSS_GPIO_Port,
		.nss_pin = RFM95_NSS_Pin,
		.nrst_port = RFM95_NRST_GPIO_Port,
		.nrst_pin = RFM95_NRST_Pin,
		.device_address = {
            0x00, 0x00, 0x00, 0x00
        },
		.application_session_key = {
            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
        },
		.network_session_key = {
            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
        },
		.receive_mode = RFM95_RECEIVE_MODE_NONE
    };

    // Initialise RFM95 module.
    if (!rfm95_init(&rfm95_handle)) {
        printf("RFM95 init failed\n\r");
    }

    uint8_t[] data_packet = {
        0x01, 0x02, 0x03, 0x4
    };

    if (!rfm95_send_receive_cycle(&rfm95_handle, data_packet, sizeof(data_packet))) {
        printf("RFM95 send failed\n\r");
    } else {
        printf("RFM95 send success\n\r");
    }
}

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
    if (GPIO_Pin == RFM95_DIO0_Pin) {
        rfm95_on_interrupt(&rfm95_handle, RFM95_INTERRUPT_DIO0);
    } else if (GPIO_Pin == RFM95_DIO1_Pin) {
        rfm95_on_interrupt(&rfm95_handle, RFM95_INTERRUPT_DIO1);
    } else if (GPIO_Pin == RFM95_DIO5_Pin) {
        rfm95_on_interrupt(&rfm95_handle, RFM95_INTERRUPT_DIO5);
    }
}

Using the reload- and safe-configuration functions

The reload_config and save_config functions can be used to store and retrieve RX and TX frame counters as well as other configuration in/from non-volatile memory. For example, when using my EEPROM library (https://github.com/henriheimann/stm32-hal-eeprom) to store the frame counters, an example implementation might look like the following:

// Forward declaration of the frame counter functions.
static bool reload_config(rfm95_eeprom_config_t *config);
static void save_config(const rfm95_eeprom_config_t *config);

// Create the handle for the RFM95 module.
rfm95_handle_t rfm95_handle = {
    // ... see example above
    .reload_config = reload_config,
    .save_config = save_config,
};

// Create the EEPROM handle.
eeprom_handle_t eeprom_handle = {
    .i2c_handle = &hi2c1,
    .device_address = EEPROM_24LC32A_ADDRESS,
    .max_address = EEPROM_24LC32A_MAX_ADDRESS,
    .page_size = EEPROM_24LC32A_PAGE_SIZE
};

static bool reload_config(rfm95_eeprom_config_t *config)
{
    return eeprom_read_bytes(&eeprom_handle, 0x0000, (uint8_t*)config, sizeof(rfm95_eeprom_config_t));
}

static void save_config(const rfm95_eeprom_config_t *config)
{
    eeprom_write_bytes(&eeprom_handle, 0x0000, (uint8_t*)config, sizeof(rfm95_eeprom_config_t));
}

Enabling Downlink Functionality

If you want to use the library's ability to receive downlink messages with MAC commands that can configure the end device, you need to provide precision clock and delay functionality as well as a few other functions. An example implementation using an STM32L4's LPTIM1 might look something like this:

// Forward declaration of the functions.
static uint32_t get_precision_tick();
static void precision_sleep_until(uint32_t target_ticks);
static uint8_t random_int(uint8_t max);
static uint8_t get_battery_level();

// Create the handle for the RFM95 module.
rfm95_handle_t rfm95_handle = {
    // ... see example above
    .precision_tick_frequency = 32768,
    .precision_tick_drift_ns_per_s = 5000,
    .receive_mode = RFM95_RECEIVE_MODE_RX12,
    .get_precision_tick = get_precision_tick,
    .precision_sleep_until = precision_sleep_until,
    .random_int = random_int,
    .get_battery_level = get_battery_level
};

volatile uint32_t lptim_tick_msb = 0;

static uint32_t get_precision_tick()
{
    __disable_irq();
    uint32_t precision_tick = lptim_tick_msb | HAL_LPTIM_ReadCounter(&hlptim1);
    __enable_irq();
    return precision_tick;
}

void HAL_LPTIM_AutoReloadMatchCallback(LPTIM_HandleTypeDef *hlptim)
{
    lptim_tick_msb += 0x10000;
}

static void precision_sleep_until(uint32_t target_ticks)
{
    while (true) {

    uint32_t start_ticks = get_precision_tick();
    if (start_ticks > target_ticks) {
        break;
    }

    uint32_t ticks_to_sleep = target_ticks - start_ticks;

    // Only use sleep for at least 10 ticks.
    if (ticks_to_sleep >= 10) {

        // Calculate required value of compare register for the sleep minus a small buffer time to compensate
        // for any ticks that occur while we perform this calculation.
        uint32_t compare = (start_ticks & 0xffff) + ticks_to_sleep - 2;

        // If the counter auto-reloads we will be woken up anyway.
        if (compare > 0xffff) {
            HAL_SuspendTick();
            HAL_PWREx_EnterSTOP2Mode(PWR_STOPENTRY_WFI);
            HAL_ResumeTick();

        // Otherwise, set compare register and use the compare match interrupt to wake up in time.
        } else {
            __HAL_LPTIM_COMPARE_SET(&hlptim1, compare);
            while (!__HAL_LPTIM_GET_FLAG(&hlptim1, LPTIM_FLAG_CMPOK));
            __HAL_LPTIM_CLEAR_FLAG(&hlptim1, LPTIM_FLAG_CMPM);
            __HAL_LPTIM_ENABLE_IT(&hlptim1, LPTIM_IT_CMPM);
            HAL_SuspendTick();
            HAL_PWREx_EnterSTOP2Mode(PWR_STOPENTRY_WFI);
            HAL_ResumeTick();
            __HAL_LPTIM_DISABLE_IT(&hlptim1, LPTIM_IT_CMPM);
        }
    } else {
        break;
    }

    // Busy wait until we have reached the target.
    while (get_precision_tick() < target_ticks);
}

static uint8_t random_int(uint8_t max)
{
    return 0; // Use ADC other means of obtaining a random number.
}

static uint8_t get_battery_level()
{
    return 0xff; // 0xff = Unknown battery level.
}

Supported Platforms

STM32L0, STM32L4 and STM32F4 microcontrollers are supported. The HAL header includes for other microcontrollers may be added in rfm95.h.

stm32-hal-rfm95's People

Contributors

henriheimann avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.