Pilote STM32 HAL pour les modules RFM95 Lorawan.
Pour les projets basés sur CMake (par exemple lorsque vous utilisez des projets STM32cubemx avec Clion), vous pouvez par exemple configurer le pilote en sous-module et lier à celui-ci:
add_subdirectory ( "<directory-to-driver>/rfm95" )
target_link_libraries (< target - name > stm32-hal-rfm95)Après avoir connecté le module RFM95 à votre microcontrôleur via SPI et initialisé le bus à l'aide du cube, vous pouvez utiliser cette bibliothèque pour interagir avec le module RFM95 comme indiqué dans l'exemple suivant. Vous devez gérer les interruptions DIO0, 1 et 5:
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 failednr" );
}
uint8_t [] data_packet = {
0x01 , 0x02 , 0x03 , 0x4
};
if (! rfm95_send_receive_cycle ( & rfm95_handle , data_packet , sizeof ( data_packet ))) {
printf ( "RFM95 send failednr" );
} else {
printf ( "RFM95 send successnr" );
}
}
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 );
}
} Les fonctions reload_config et save_config peuvent être utilisées pour stocker et récupérer les compteurs de trame RX et TX ainsi que d'autres configurations dans / depuis la mémoire non volatile. Par exemple, lorsque vous utilisez ma bibliothèque EEPROM (https://github.com/henriheimann/stm32-hal-eprom) pour stocker les compteurs de trame, un exemple d'implémentation peut ressembler à ce qui suit:
// 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 ));
}Si vous souhaitez utiliser la capacité de la bibliothèque à recevoir des messages de liaison descendante avec des commandes MAC qui peuvent configurer le périphérique final, vous devez fournir des fonctionnalités d'horloge et de retard de précision ainsi que quelques autres fonctions. Un exemple d'implémentation à l'aide d'un LPTIM1 de STM32L4 pourrait ressembler à ceci:
// 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.
} Les microcontrôleurs STM32L0, STM32L4 et STM32F4 sont pris en charge. L'en-tête HAL comprend pour d'autres microcontrôleurs peut être ajouté dans rfm95.h .