lr20xx: bump vendored SDK to v2.0.2 and load the firmware Patch RAM

This commit is contained in:
liquidraver
2026-08-11 22:36:31 +02:00
parent ab03be110e
commit 101e97f54a
29 changed files with 2801 additions and 629 deletions
+1
View File
@@ -140,3 +140,4 @@ handover_thinknode_m9.md
# Vendor reference docs (datasheets, errata). Local only — not ours to redistribute.
/datasheets/
LR2021_AUDIT_INDEX.md
@@ -0,0 +1,30 @@
License for the code produced by Semtech contained in this project
------------------------------------------------------------------
The Clear BSD License
Copyright Semtech Corporation 2022. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted (subject to the limitations in the disclaimer
below) provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the Semtech corporation nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY
THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT
NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SEMTECH CORPORATION BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
@@ -57,7 +57,7 @@ extern "C" {
/**
* @brief Value of driver version string
*/
#define LR20XX_DRIVER_VERSION "v1.3.4"
#define LR20XX_DRIVER_VERSION "v2.0.2"
/*
* -----------------------------------------------------------------------------
+1 -1
View File
@@ -67,7 +67,7 @@ extern "C" {
typedef enum lr20xx_hal_status_e
{
LR20XX_HAL_STATUS_OK = 0,
LR20XX_HAL_STATUS_ERROR = 3, /* Must match lr20xx_status_t ERROR value */
LR20XX_HAL_STATUS_ERROR = 3,
} lr20xx_hal_status_t;
/*
@@ -0,0 +1,173 @@
/*!
* @file lr20xx_patch.c
*
* @brief Implementation of patching commands for LR20XX
*
* The Clear BSD License
* Copyright Semtech Corporation 2026. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted (subject to the limitations in the disclaimer
* below) provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the Semtech corporation nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY
* THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT
* NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SEMTECH CORPORATION BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* -----------------------------------------------------------------------------
* --- DEPENDENCIES ------------------------------------------------------------
*/
#include <stdbool.h> // true, false
#include "lr20xx_patch.h"
#include "lr20xx_regmem.h"
#include "lr20xx_hal.h"
/*
* -----------------------------------------------------------------------------
* --- PRIVATE MACROS-----------------------------------------------------------
*/
#define LR20XX_PATCH_MAGIC_WORD_ADDRESS ( 0x800FF8 )
#define LR20XX_PATCH_TYPE_VERSION_ADDRESS ( 0x800FFC )
#define LR20XX_PATCH_MAGIC_WORD_EXPECTED ( 0x600DB002 )
#define LR20XX_PRAM_BASE_ADDRESS ( 0x801000 )
#define LR20XX_PATCH_ENABLE_PRAM_CMD_LENGTH ( 2 + 1 )
/*
* -----------------------------------------------------------------------------
* --- PRIVATE CONSTANTS -------------------------------------------------------
*/
/*
* -----------------------------------------------------------------------------
* --- PRIVATE TYPES -----------------------------------------------------------
*/
/*!
* @brief Operating codes for patch RAM related operations
*/
enum
{
LR20XX_PATCH_ENABLE_PRAM_OC = 0x012D,
};
/*
* -----------------------------------------------------------------------------
* --- PRIVATE VARIABLES -------------------------------------------------------
*/
/*
* -----------------------------------------------------------------------------
* --- PRIVATE FUNCTIONS DECLARATION -------------------------------------------
*/
/*
* -----------------------------------------------------------------------------
* --- PUBLIC FUNCTIONS DEFINITION ---------------------------------------------
*/
lr20xx_status_t lr20xx_patch_load_pram( const void* context, const uint32_t address, const uint32_t* buffer,
const uint32_t length )
{
// The pram is written by blocks of 32 words
const uint32_t n_32_word_blocks = length / 32u;
// Write all blocks of 32 words
for( uint32_t index_32_word_block = 0; index_32_word_block < n_32_word_blocks; index_32_word_block++ )
{
const uint32_t* local_buffer = buffer + ( index_32_word_block * 32u );
const uint32_t local_address = address + ( index_32_word_block * 32u * 4u );
const lr20xx_status_t status = lr20xx_regmem_write_regmem32( context, local_address, local_buffer, 32u );
if( status != LR20XX_STATUS_OK )
{
return status;
}
}
// Check if there are remaining words to write and if so, write it in a single call
const uint8_t n_remaining_words = ( uint8_t ) ( length - ( n_32_word_blocks * 32u ) );
if( n_remaining_words > 0 )
{
const lr20xx_status_t status =
lr20xx_regmem_write_regmem32( context, address + ( n_32_word_blocks * 32u * 4u ),
buffer + ( n_32_word_blocks * 32u ), n_remaining_words );
return status;
}
else
{
return LR20XX_STATUS_OK;
}
}
lr20xx_status_t lr20xx_patch_enable_pram( const void* context )
{
const uint8_t cbuffer[LR20XX_PATCH_ENABLE_PRAM_CMD_LENGTH] = {
( uint8_t ) ( LR20XX_PATCH_ENABLE_PRAM_OC >> 8 ),
( uint8_t ) ( LR20XX_PATCH_ENABLE_PRAM_OC >> 0 ),
0,
};
return ( lr20xx_status_t ) lr20xx_hal_write( context, cbuffer, LR20XX_PATCH_ENABLE_PRAM_CMD_LENGTH, 0, 0 );
}
lr20xx_status_t lr20xx_patch_get_version( const void* context, lr20xx_patch_version_t* pram_version )
{
// 1. Read the magic word register
uint32_t magic_word_read = 0;
const lr20xx_status_t magic_word_read_status =
lr20xx_regmem_read_regmem32( context, LR20XX_PATCH_MAGIC_WORD_ADDRESS, &magic_word_read, 1 );
if( magic_word_read_status == LR20XX_STATUS_OK )
{
// 2. If magic word register content match expectation, a PRAM is loaded
if( magic_word_read == LR20XX_PATCH_MAGIC_WORD_EXPECTED )
{
// 3. Read the PRAM type and version register
uint32_t pram_type_version_raw = 0;
const lr20xx_status_t pram_type_version_read_status =
lr20xx_regmem_read_regmem32( context, LR20XX_PATCH_TYPE_VERSION_ADDRESS, &pram_type_version_raw, 1 );
if( pram_type_version_read_status == LR20XX_STATUS_OK )
{
pram_version->is_pram_loaded = true;
pram_version->pram_type = ( uint8_t ) ( pram_type_version_raw >> 16 );
pram_version->pram_version = ( uint8_t ) ( pram_type_version_raw >> 8 );
}
return pram_type_version_read_status;
}
else
{
pram_version->is_pram_loaded = false;
pram_version->pram_type = 0;
pram_version->pram_version = 0;
}
}
return magic_word_read_status;
}
/*
* -----------------------------------------------------------------------------
* --- PRIVATE FUNCTIONS DEFINITION --------------------------------------------
*/
/* --- EOF ------------------------------------------------------------------ */
@@ -0,0 +1,128 @@
/*!
* @file lr20xx_patch.h
*
* @brief Patching commands for Lr20xx
*
* The Clear BSD License
* Copyright Semtech Corporation 2026. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted (subject to the limitations in the disclaimer
* below) provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the Semtech corporation nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY
* THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT
* NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SEMTECH CORPORATION BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef LR20XX_PATCH_H
#define LR20XX_PATCH_H
#ifdef __cplusplus
extern "C" {
#endif
/*
* -----------------------------------------------------------------------------
* --- DEPENDENCIES ------------------------------------------------------------
*/
#include <stdint.h>
#include "lr20xx_patch_types.h"
#include "lr20xx_status.h"
/*
* -----------------------------------------------------------------------------
* --- PUBLIC MACROS -----------------------------------------------------------
*/
/*
* -----------------------------------------------------------------------------
* --- PUBLIC CONSTANTS --------------------------------------------------------
*/
/*
* -----------------------------------------------------------------------------
* --- PUBLIC TYPES ------------------------------------------------------------
*/
/*
* -----------------------------------------------------------------------------
* --- PUBLIC FUNCTIONS PROTOTYPES ---------------------------------------------
*/
/**
* @brief Transfer a Patch RAM (PRAM) into the chip
*
* This function is a helper function that execute several calls to @ref lr20xx_regmem_write_regmem32 in order to
* transfer the complete PRAM.
* After loading the PRAM with @ref lr20xx_patch_load_pram, it must be enabled by calling @ref lr20xx_patch_enable_pram.
*
* @note The helper functions @ref lr20xx_pram_load_pram_lr2021 and @ref lr20xx_pram_load_pram_lr20x2 handle the load
* and enabling of the appropriate PRAM.
*
* @param context Chip implementation context
* @param address The base address in the chip memory where the PRAM is to be written
* @param buffer Pointer to the buffer being the PRAM data to transfer. It is up to the caller to ensure it contains at
* least @p length elements
* @param length Number of elements fro @p buffer array to write
*
* @return lr20xx_status_t Operation status
*
* @see lr20xx_patch_enable_pram, lr20xx_regmem_write_regmem32, lr20xx_patch_get_version
*/
lr20xx_status_t lr20xx_patch_load_pram( const void* context, const uint32_t address, const uint32_t* buffer,
const uint32_t length );
/**
* @brief Enable Patch RAM (PRAM)
*
* This function must be called after @ref lr20xx_patch_load_pram to enable the PRAM usage.
*
* @param context Chip implementation context
*
* @return lr20xx_status_t Operation status
*
* @see lr20xx_patch_load_pram, lr20xx_patch_get_version, lr20xx_pram_load_pram_lr2021, lr20xx_pram_load_pram_lr20x2
*/
lr20xx_status_t lr20xx_patch_enable_pram( const void* context );
/**
* @brief Get Patch RAM (PRAM) version information
*
* This function can be called after @ref lr20xx_patch_load_pram to check that PRAM has been correctly loaded.
*
* @param context Chip implementation context
* @param pram_version The version information of the PRAM. Only valid if function returned with status @ref
* LR20XX_STATUS_OK
*
* @return lr20xx_status_t Operation status
*
* @see lr20xx_patch_load_pram, lr20xx_patch_enable_pram, lr20xx_pram_load_pram_lr2021, lr20xx_pram_load_pram_lr20x2
*/
lr20xx_status_t lr20xx_patch_get_version( const void* context, lr20xx_patch_version_t* pram_version );
#ifdef __cplusplus
}
#endif
#endif // LR20XX_PATCH_H
/* --- EOF ------------------------------------------------------------------ */
@@ -0,0 +1,92 @@
/*!
* @file lr20xx_patch_types.h
*
* @brief Patch types driver definition for LR20XX
*
* The Clear BSD License
* Copyright Semtech Corporation 2026. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted (subject to the limitations in the disclaimer
* below) provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the Semtech corporation nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY
* THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT
* NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SEMTECH CORPORATION BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef LR20XX_PATCH_TYPES_H
#define LR20XX_PATCH_TYPES_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <stdbool.h>
/*
* -----------------------------------------------------------------------------
* --- DEPENDENCIES ------------------------------------------------------------
*/
/*
* -----------------------------------------------------------------------------
* --- PUBLIC MACROS -----------------------------------------------------------
*/
/*
* -----------------------------------------------------------------------------
* --- PUBLIC CONSTANTS --------------------------------------------------------
*/
/*
* -----------------------------------------------------------------------------
* --- PUBLIC TYPES ------------------------------------------------------------
*/
/**
* @brief PRAM version information
*
* @ref lr20xx_patch_version_e::is_pram_loaded indicates if a PRAM is loaded.
* If @ref lr20xx_patch_version_e::is_pram_loaded is true then lr20xx_patch_version_e::pram_type contains the type of
* PRAM, and lr20xx_patch_version_e::pram_version contains the version of the loaded PRAM. If @ref
* lr20xx_patch_version_e::is_pram_loaded is false, then value of fields lr20xx_patch_version_e::pram_type and
* lr20xx_patch_version_e::pram_version are undefined, and should not be read.
*/
typedef struct lr20xx_patch_version_e
{
bool is_pram_loaded; //!< True if the PRAM is loaded, false otherwise
uint8_t pram_type; //!< Type of the loaded PRAM, if lr20xx_patch_version_e::is_pram_loaded is true
uint8_t pram_version; //!< Version of the loaded PRAM, if lr20xx_patch_version_e::is_pram_loaded is true
} lr20xx_patch_version_t;
/*
* -----------------------------------------------------------------------------
* --- PUBLIC FUNCTIONS PROTOTYPES ---------------------------------------------
*/
#ifdef __cplusplus
}
#endif
#endif // LR20XX_PATCH_TYPES_H
/* --- EOF ------------------------------------------------------------------ */
@@ -0,0 +1,123 @@
/*!
* @file lr20xx_pram_lr2021.h
*
* @brief LR2021 firmware Patch RAM (PRAM) image
*
* The Clear BSD License
* Copyright Semtech Corporation 2026. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted (subject to the limitations in the disclaimer
* below) provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the Semtech corporation nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY
* THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT
* NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SEMTECH CORPORATION BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Vendored verbatim from Lora-net/usp, tag v1.1.2-feature-202604,
* smtc_rac_lib/radio_drivers/lr20xx_driver/inc/lr20xx_pram_lr2021.h
* (lr20xx_driver v2.0.2). Upstream ships this file with no per-file notice;
* the header above is the standard Semtech Clear BSD notice carried by every
* other file in that directory and reproduced here because the Clear BSD terms
* require the copyright notice to be retained on redistribution. The array
* contents below are byte-for-byte upstream.
*
* See LR20xx datasheet rev 2.1 section 22.3 for what the PRAM is and why it
* must be loaded after every reset.
*
* NOTE: `pram_lr2021` and `pram_lr2021_size` are const definitions at file
* scope, which in C have external linkage — include this header from exactly
* one translation unit (lr20xx_lora.c) or the link will fail with duplicate
* symbols.
*/
#ifndef LR20XX_PRAM_LR2021_H
#define LR20XX_PRAM_LR2021_H
#include <stdint.h>
const uint32_t pram_lr2021_size = 560;
const uint32_t pram_lr2021[560] = {
0x600db002, 0x31304, 0x10104c, 0x101018, 0x0, 0x0, 0x40c3c0f1, 0x88000, 0x212a,
0xff82184, 0x212bb986, 0x40c30000, 0x9680080, 0x1800d981, 0xb90d0041, 0x8040c3, 0x794077f8, 0x7fe0c0d1,
0x78e0720c, 0x45cbc2e4, 0x77f80080, 0x10011d00, 0x41c358bf, 0x18c00010, 0x8046cb, 0xe81a0968, 0xf80212b,
0x2900000, 0x70148600, 0x41c3f2ac, 0x88000, 0x40202a, 0xff82084, 0x202bb886, 0xd9810040, 0x40a1b90d,
0x1e007960, 0xf09c1041, 0x852f0b0e, 0x307208a, 0x146208a, 0x1041c3, 0xbe2134c, 0x1e00856f, 0x41c31001,
0x120c0010, 0x856f0bd2, 0x41c3d83d, 0x11d80010, 0x856f0bc6, 0x41c3d835, 0x13940010, 0x856f0bba, 0x786208a,
0x1041c3, 0xbae13b4, 0x208a856f, 0x41c30846, 0x14580010, 0x856f0b9e, 0x41c3d848, 0x143c0010, 0x856f0b92,
0x41c3d847, 0x14240010, 0x856f0b86, 0x41c3d845, 0x15840010, 0x856f0b7a, 0x41c3d8e0, 0x15580010, 0x856f0b6e,
0x41c3d8dc, 0x16080010, 0x856f0b62, 0x304208a, 0x1041c3, 0xb5615d0, 0x208a856f, 0x41c302c4, 0x16680010,
0x856f0b46, 0x4c4208a, 0x1041c3, 0xb3a1640, 0x208a856f, 0x41c30484, 0x13740010, 0x856f0b2a, 0x186208a,
0x1041c3, 0xb1e1470, 0xd882856f, 0x1041c3, 0xb121690, 0x208a856f, 0x41c30504, 0x184c0010, 0x856f0b02,
0x87208a, 0x1041c3, 0xaf617f0, 0x208a856f, 0x41c30cc6, 0x18040010, 0x856f0ae6, 0xdc6208a, 0x1041c3,
0xada15ac, 0xd8f6856f, 0x1040c3, 0x80401000, 0x40c38021, 0xff80080, 0xa021a040, 0x90a, 0xcf6,
0xc6c4720c, 0x47cbc2e6, 0x20000f4, 0xb98dd9f0, 0x87c07960, 0x87004508, 0x120126ad, 0x10710e0d, 0x20120ad,
0x95080d, 0x10940e0d, 0x510809, 0x8d2, 0xc6c640a1, 0x1cfcc2e6, 0xc1a1b6c8, 0x8044cb, 0x84800968,
0x46484768, 0x43184528, 0x40c3ec0f, 0x77f80080, 0xec0b8080, 0x41a14063, 0x7c6042c1, 0x208c43e1, 0xc0408fc3,
0x238cf443, 0xf227b7c2, 0xb2c1238c, 0x238cf229, 0xf22db682, 0x30310b63, 0x16004063, 0x807080, 0x7514600b,
0xc040700c, 0x710cf22f, 0x11340d5b, 0x40c1c040, 0x45cb5839, 0x60500080, 0x734c712c, 0x5981a520, 0x10011d00,
0x84ee89f, 0x720c0000, 0x40a1f01a, 0xc4641c1, 0x42e10020, 0x40a1f014, 0x9ee41c1, 0x42e10020, 0x40a1f00e,
0xa4a41c1, 0x42e10020, 0x44cbf008, 0x24e00000, 0x42c141a1, 0x43e17c60, 0xc000c040, 0x7487780f, 0x341b1404,
0x78e0c6c6, 0x42c3c2e2, 0x2400f2, 0x8040c3, 0x88000773, 0x710811, 0x250582a0, 0xf01f80, 0xf0270000,
0xf441c3, 0x81000200, 0x1c2084, 0x8004208c, 0x43c3f405, 0xcccc0044, 0x43c3f004, 0xcccc002c, 0x8044cb,
0xa460004c, 0x80001144, 0x2d0070d3, 0x25040000, 0xff0f1f80, 0xf788ffff, 0x797db894, 0xb897b896, 0xf003a420,
0xa200b897, 0x70001600, 0x14400f4, 0xc6c25852, 0x1600c2e2, 0x80708d, 0x42c30773, 0xfdc00000, 0x16007a40,
0x807081, 0x75300773, 0xffe20f6c, 0x40a14508, 0x78e0c6c2, 0x3e0817, 0x40c34408, 0x9680080, 0xb8028800,
0x204f7885, 0x788f004c, 0x44cb, 0x7c00feb0, 0x8041c3, 0x89200773, 0x42c3e987, 0x2400f2, 0xb9ad8220,
0x41c3a220, 0x101c0001, 0x78e07900, 0x40c3c0f1, 0x13b00001, 0x40c37840, 0x2400f2, 0xb98d8020, 0x7fe0c0d1,
0xa020, 0x70811600, 0x2a10080, 0x837690a, 0x713400b5, 0xf341c3, 0x81000c14, 0x2822150, 0x180206c,
0xf012085, 0x8105a100, 0x7f02084, 0xf2085, 0x8200a105, 0x1c0206c, 0x7fe0b880, 0x7de0a200, 0xf340c3,
0x80200814, 0xb993b9d2, 0xb995b994, 0xa0207fe0, 0x40c3c0f1, 0x269c0000, 0xfa67840, 0x4300ffef, 0x7fe0c0d1,
0x78e04060, 0xc1a1c3e2, 0x45cbc404, 0x27500000, 0xc4407d60, 0xffef0f86, 0x40604300, 0x78e0c7c2, 0x42c3c0f1,
0x27b80000, 0xf727a40, 0x4300ffef, 0x7fe0c0d1, 0x78e04060, 0x43c3c0f1, 0x4f280000, 0x42c37b40, 0xd2400f3,
0xb9dd8220, 0x7fe0c0d1, 0x78e0a220, 0x872c2e4, 0x454881ef, 0x88418521, 0x8840a940, 0xa9418521, 0x90218541,
0xaa22793d, 0x85618824, 0x8042c3, 0x793d77fc, 0x8824ab23, 0x88058862, 0x4c2144, 0xb8046b32, 0x1032144,
0x204485c1, 0x23050c01, 0x78250300, 0x8240ae04, 0x2a418501, 0xa8250401, 0x2012a41, 0xa8268501, 0xa8478501,
0x1d00730c, 0xc6c41201, 0xcdec2e4, 0x4548802f, 0x85014608, 0xa8208e29, 0x85018e28, 0x8521a821, 0x781d9605,
0x9606a902, 0x781d8521, 0x886f0d06, 0x8521a903, 0x9606a904, 0x20449625, 0x69120042, 0x20448521, 0x78450100,
0x8e12a905, 0xa9068521, 0x40c38561, 0x78080080, 0x11c11d00, 0x8b458800, 0x79456833, 0xab25730c, 0x78e0c6c4,
0xfd2c2e2, 0x4508838f, 0x40c3, 0x78408db8, 0xf340c3, 0x80200b74, 0x4012184, 0x411090f, 0x8ba8001,
0x780f836f, 0xc6c2ad08, 0x43c3c2e2, 0x8eb80000, 0x45087b60, 0xf344cb, 0x84600b50, 0x10022578, 0x2304ba18,
0xf8ff0f81, 0x7945ffff, 0xc6c2a420, 0x45cbc2e4, 0x14400f4, 0x40c3, 0x78609fec, 0x850085c0, 0x781178c2,
0xa070d3, 0xd0c0001, 0xc6c4ffc6, 0x41c3c2e2, 0xa9680000, 0x82b7940, 0x45080131, 0x820f0aee, 0x111081f,
0xf442c3, 0x82200144, 0x8040c3, 0x18007800, 0xa0210041, 0x180216c, 0x40a1a200, 0x78e0c6c2, 0x41c3c2e2,
0xaad40000, 0x82b7940, 0x45080171, 0x820f0ab6, 0x111081f, 0xf442c3, 0x82200144, 0x8040c3, 0x18007800,
0xa0210041, 0x180216c, 0x40a1a200, 0x78e0c6c2, 0x40c3c0f1, 0xb15c0000, 0x42c37840, 0x78000080, 0xe9098220,
0x1a008221, 0x1e000001, 0xf47040, 0xc0d10144, 0x78e07ee0, 0x40c3c0f1, 0xb2b00000, 0x42c37840, 0x78000080,
0xe9098220, 0x1a008221, 0x1e000001, 0xf47040, 0xc0d10144, 0x78e07ee0, 0x41c3c2e2, 0xb3dc0000, 0xa367940,
0x827820f, 0x16000151, 0xf37000, 0x45cb0d3c, 0x77fc0080, 0xb0ab854, 0xa500802f, 0x85008030, 0xb94c790c,
0xc6c2a520, 0x8041c3, 0x40c37800, 0x3930, 0x11900, 0xa1017fe0, 0x1cfcc2e6, 0xc1a3b6c8, 0x85b4528,
0x716f01b4, 0x8d838d05, 0x8d648dc0, 0x8d428d21, 0x8f206d, 0xc041b8c0, 0x12002c40, 0x40c17b05, 0xdbec742,
0x1c0082af, 0x26053081, 0xf415903e, 0x42c38d05, 0x83000f3, 0x78128220, 0xb9b9b818, 0x800212fc, 0xf802004,
0x200, 0xb826038, 0x4100862f, 0x4063726f, 0x1404c0a3, 0xc6c6341b, 0xa76c2e6, 0x1048800f, 0x8a30080,
0x244a0071, 0x41c37200, 0x6faa00b1, 0xf342c3, 0x40c30c18, 0x6faa004e, 0x501a04, 0x59c343c3, 0x1a04ae57,
0x22500010, 0x1a040281, 0x820000d0, 0xff7d44cb, 0x43c3d5f7, 0x7f5dff7d, 0xf802004, 0xfffc07ff, 0xf802005,
0x1f800, 0xa180a200, 0x8102a161, 0x9f4643c3, 0x206c0012, 0xb8850180, 0xa261a102, 0x800012f0, 0x43c370ad,
0x18b00010, 0x180206c, 0x2045bd93, 0x23400300, 0x41a1020c, 0x10cf2d41, 0x80001af0, 0x2c020a8, 0x14c01401,
0x4ce1301, 0xbe087825, 0x78c561f9, 0xc6c6a206, 0x40c3c0f1, 0x1ac00001, 0xf4e7840, 0xc0d1ffcf, 0x78e07ee0,
0xc1a5c3e6, 0xc00a4608, 0x4328c40c, 0xc50bc10e, 0xc040c70d, 0x9fc3248c, 0x20ca4081, 0xe68b0321, 0xc541c144,
0x100124ca, 0x145cb, 0x40c11e7c, 0xc7434161, 0xc4427d60, 0xe68a4508, 0xffef0f06, 0x106125ca, 0xc7c640a1,
0x41c3c0f1, 0x60c90080, 0x1e008900, 0x807002, 0x11ff0584, 0x40c38081, 0x78080080, 0xb76a020, 0x730c84ef,
0x884f0c0a, 0x7ee0c0d1, 0x2494e49, 0x1018c0, 0xfffff8d0, 0x800968, 0xfffff970, 0x8077f8, 0x14,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf7e41c09, 0x1f20201f,
0xe10f0fe1, 0xf9fffff9
};
#endif // LR20XX_PRAM_LR2021_H
@@ -49,13 +49,21 @@
* --- PRIVATE MACROS-----------------------------------------------------------
*/
/* LR2021 internal RTC: 32.768kHz (datasheet §5.3) */
/**
* @brief Internal RTC frequency
*/
#define LR20XX_RTC_FREQ_IN_HZ ( 32768UL )
/* Front-end calibration granularity: 4MHz steps (LR2021 datasheet §5.5.1) */
/*!
* @brief Frequency step in Hz used to compute the front end calibration parameter
*
* @see lr20xx_radio_common_calibrate_front_end_helper
*/
#define LR20XX_RADIO_COMMON_FRONT_END_CALIBRATION_STEP_IN_HZ ( 4000000u )
/* LR2021 register: LQI (Link Quality Indicator) — Semtech SWDR001 register map */
/**
* Register address holding the LQI value
*/
#define LR20XX_RADIO_COMMON_REGISTER_LQI ( 0xF30C38 )
/*
@@ -145,13 +153,27 @@ enum
* --- PRIVATE FUNCTIONS DECLARATION -------------------------------------------
*/
/* Serialize one RSSI calibration gain item; returns pointer past written data.
* Caller ensures array has sufficient space. */
/*!
* @brief Serialize an RSSI calibration item into an array
*
* @param array Pointer to the array to write to. It is up to the caller to ensure the array is long enough to store the
* serialized item
* @param rssi_calibration_item Pointer to the RSSI calibration item to serialize. It is up to the caller to ensure it
* points to an actual item.
* @return uint8_t* Pointer to the next memory slot to write
*/
uint8_t* lr20xx_radio_common_serialize_rssi_calibration_item(
uint8_t* array, const lr20xx_radio_common_rssi_calibration_gain_item_t* rssi_calibration_item );
/* Serialize a full RSSI calibration gain table; no-op if rssi_calibration_table is NULL.
* Returns pointer past written data. */
/**
* @brief Serialize an RSSI calibration table into an array
*
* @param array Pointer to the array to write to. It is up to the caller to ensure the array is long enough to store the
* serialized table
* @param rssi_calibration_table Pointer to the calibration table to serialize. Can be NULL, in which case nothing is
* written to the array
* @return uint8_t* Pointer to the next memory slot to write
*/
uint8_t* lr20xx_radio_common_serialize_rssi_calibration_table(
uint8_t* array, const lr20xx_radio_common_rssi_calibration_gain_table_t* rssi_calibration_table );
@@ -237,17 +259,7 @@ lr20xx_status_t lr20xx_radio_common_set_rx_path( const void* context, lr20xx_rad
( uint8_t ) boost_mode,
};
const lr20xx_status_t write_status =
( lr20xx_status_t ) lr20xx_hal_write( context, cbuffer, LR20XX_RADIO_COMMON_SET_RX_PATH_CMD_LENGTH, 0, 0 );
if( write_status != LR20XX_STATUS_OK )
{
return write_status;
}
else
{
return LR20XX_WORKAROUNDS_CONDITIONAL_APPLY_AUTOMATIC_DCDC_CONFIGURE( context );
}
return ( lr20xx_status_t ) lr20xx_hal_write( context, cbuffer, LR20XX_RADIO_COMMON_SET_RX_PATH_CMD_LENGTH, 0, 0 );
}
lr20xx_status_t lr20xx_radio_common_set_pa_cfg( const void* context, const lr20xx_radio_common_pa_cfg_t* pa_cfg )
@@ -330,17 +342,7 @@ lr20xx_status_t lr20xx_radio_common_set_pkt_type( const void* context, lr20xx_ra
( uint8_t ) pkt_type,
};
const lr20xx_status_t write_status =
( lr20xx_status_t ) lr20xx_hal_write( context, cbuffer, LR20XX_RADIO_COMMON_SET_PKT_TYPE_CMD_LENGTH, 0, 0 );
if( write_status != LR20XX_STATUS_OK )
{
return write_status;
}
else
{
return LR20XX_WORKAROUNDS_CONDITIONAL_APPLY_AUTOMATIC_DCDC_RESET( context );
}
return ( lr20xx_status_t ) lr20xx_hal_write( context, cbuffer, LR20XX_RADIO_COMMON_SET_PKT_TYPE_CMD_LENGTH, 0, 0 );
}
lr20xx_status_t lr20xx_radio_common_get_pkt_type( const void* context, lr20xx_radio_common_pkt_type_t* pkt_type )
@@ -69,169 +69,577 @@ extern "C" {
* --- PUBLIC FUNCTIONS PROTOTYPES ---------------------------------------------
*/
/*
* Calibrate front-end (ADC offset, poly-phase filter, image) from raw calibration values.
* Must be called when chip is not in Rx/Tx. Up to 3 values; 0 calibrates at next 4MHz multiple of current RF freq.
* RF ops should stay within 50MHz of a calibrated frequency. Errors readable via lr20xx_system_get_errors.
/*!
* @brief Executes front end calibration procedure on given raw frequencies and Rx path
*
* The front end calibration calibrates:
* - the ADC offset
* - the poly-phase filter
* - the image
* This function can be called only if the chip is neither in Rx nor Tx states.
*
* Upon completion, the chip will return to the same mode it was before calling this command.
* Potential calibration issues can be read out with lr20xx_system_get_errors command.
*
* Up to three calibration configuration values can be given.
* Only the provided and non-zero frequencies are calibrated.
*
* It is advised to configure calibration so that RF frequencies used during RF operations are at most 50MHz away from
* a calibrated RF frequency.
*
* If no calibration configuration is given, then one front end calibration is executed on the next 4MHz multiple of the
* currently configured RF frequency.
*
* @param [in] context Chip implementation context
* @param [in] front_end_calibration_values Array of front end calibration configuration. It is up to the caller to
* ensure that it has at least n_rx_path_frequency elements.
* @param [in] n_front_end_calibration_values Number of front end calibration values to consider. Valid values are [0:3]
* included.
*
* @returns Operation status
*
* @see lr20xx_system_get_errors, lr20xx_radio_common_calibrate_front_end_helper
*/
lr20xx_status_t lr20xx_radio_common_calibrate_front_end(
const void* context, const lr20xx_radio_common_raw_front_end_calibration_value_t* front_end_calibration_values,
uint8_t n_front_end_calibration_values );
/*
* Helper: converts front_end_calibration_value_t structs to raw values and calls calibrate_front_end.
* Each frequency is rounded up to the next 4MHz multiple.
/*!
* @brief Helper function to execute front end calibration procedure
*
* This function really is a helper function that converts the front end calibration structures in argument to the
* corresponding raw values, and calls @ref lr20xx_radio_common_calibrate_front_end.
* For each given front end calibration frequency, the actual calibration frequency used is the next frequency multiple
* of 4MHz following the given frequency.
*
* @param [in] context Chip implementation context
* @param [in] front_end_calibration_structures Array of front end calibration configuration structures. It is up to the
* user that it contains at least n_rx_path_frequency items.
* @param [in] n_front_end_calibration_structures Number of front end calibration structures to consider. Valid values
* are [0:3] included.
*
* @returns Operation status
*
* @see lr20xx_radio_common_calibrate_front_end
*/
lr20xx_status_t lr20xx_radio_common_calibrate_front_end_helper(
const void* context, const lr20xx_radio_common_front_end_calibration_value_t* front_end_calibration_structures,
uint8_t n_front_end_calibration_structures );
/* Convert milliseconds to 32.768kHz RTC step count */
/**
* @brief Helper function that computes the number of RTC steps from a given time in millisecond
*
* @param [in] time_in_ms Time in millisecond
*
* @returns Number of RTC steps
*/
uint32_t lr20xx_radio_common_convert_time_in_ms_to_rtc_step( uint32_t time_in_ms );
/*!
* @brief Set the RF frequency to be used
*
* @param [in] context Chip implementation context
* @param [in] freq_in_hz RF frequency in Hertz
*
* @returns Operation status
*/
lr20xx_status_t lr20xx_radio_common_set_rf_freq( const void* context, uint32_t freq_in_hz );
/*!
* @brief Select the Rx path and set the boost mode
*
* @param [in] context Chip implementation context
* @param [in] rx_path Rx path to be used
* @param [in] boost_mode Boost mode applied to selected Rx path
*
* @returns Operation status
*/
lr20xx_status_t lr20xx_radio_common_set_rx_path( const void* context, lr20xx_radio_common_rx_path_t rx_path,
lr20xx_radio_common_rx_path_boost_mode_t boost_mode );
/* Must be called before lr20xx_radio_common_set_tx_params */
/*!
* @brief Set the Power Amplifier configuration
*
* It must be called prior using @ref lr20xx_radio_common_set_tx_params.
*
* @param [in] context Chip implementation context
* @param [in] pa_cfg The structure for PA configuration
*
* @see lr20xx_radio_common_set_tx_params
*
* @returns Operation status
*/
lr20xx_status_t lr20xx_radio_common_set_pa_cfg( const void* context, const lr20xx_radio_common_pa_cfg_t* pa_cfg );
/*
* Set TX output power (0.5dBm steps) and PA ramp time. Requires prior call to set_pa_cfg.
* LF PA: power_half_dbm in [0xED, 0x2C] (-9.5 to +22dBm)
* HF PA: power_half_dbm in [0xD9, 0x18] (-19.5 to +12dBm)
/*!
* @brief Set the parameters for TX power and power amplifier ramp time
*
* @ref lr20xx_radio_common_set_pa_cfg must be called prior calling lr20xx_radio_common_set_tx_params.
*
* The range of possible TX output power values depends on PA selected with @ref
* lr20xx_radio_common_set_pa_cfg :
* - for @ref LR20XX_RADIO_COMMON_PA_SEL_LF : power value goes from -9.5dBm to +22dBm
* (ie. @p power_half_dbm from 0xED to 0x2C)
* - for @ref LR20XX_RADIO_COMMON_PA_SEL_HF : power value goes from -19.5dBm to +12dBm
* (ie. @p power_half_dbm from 0xD9 to 0x18)
*
* @param [in] context Chip implementation context
* @param [in] power_half_dbm TX output power raw value, as 0.5dBm steps (so twice the value in dBm)
* @param [in] ramp_time Ramping time configuration
*
* @see lr20xx_radio_common_set_pa_cfg
*
* @returns Operation status
*/
lr20xx_status_t lr20xx_radio_common_set_tx_params( const void* context, const int8_t power_half_dbm,
const lr20xx_radio_common_ramp_time_t ramp_time );
/* Set RSSI calibration gain tables; NULL pointer skips that path */
/*!
* @brief Set RSSI calibration table(s)
*
* @param [in] context Chip implementation context
* @param [in] rssi_cal_table_lf Pointer to RSSI calibration table for low frequency path. Can be NULL, in which case
* this path is not configured
* @param [in] rssi_cal_table_hf Pointer to RSSI calibration table for high frequency path. Can be NULL, in which case
* this path is not configured
*
* @returns Operation status
*/
lr20xx_status_t lr20xx_radio_common_set_rssi_calibration(
const void* context, const lr20xx_radio_common_rssi_calibration_gain_table_t* rssi_cal_table_lf,
const lr20xx_radio_common_rssi_calibration_gain_table_t* rssi_cal_table_hf );
/*
* Set chip mode after leaving Tx/Rx (successful, timeout, or CAD).
* Applied on: TX done, RX done (non-continuous), RX duty cycle done, CAD exit, timeout, auto-Tx/Rx transitions.
/*!
* @brief Configure the chip mode shall be in after transmission or reception operation
*
* @remark The configured fallback mode is applied as soon as the chip leaves Tx / Rx mode:
* - after a successful transmission
* - after a successful reception if not set in continuous mode
* - after a successful reception in duty cycle mode
* - after a CAD operation (depending on configured exit mode)
* - when a timeout occurs
* - during automatic Tx/Rx (see @ref lr20xx_radio_common_configure_auto_tx_rx), both after the first Rx/Tx and the
* second Tx/Rx
*
* @param [in] context Chip implementation context
* @param [in] fallback_mode Chip mode to enter after transmission or reception operation
*
* @returns Operation status
*/
lr20xx_status_t lr20xx_radio_common_set_rx_tx_fallback_mode( const void* context,
const lr20xx_radio_common_fallback_modes_t fallback_mode );
/*
* Set packet type; must precede any modulation configuration.
* Automatically applies lr20xx_workarounds_dcdc_reset unless LR20XX_WORKAROUNDS_DISABLE_AUTOMATIC_DCDC_RESET is defined.
/*!
* @brief Set the packet type to be used
*
* @remark This command has to be sent prior to any modulation related configuration command
*
* @param [in] context Chip implementation context
* @param [in] pkt_type Packet type to be configured
*
* @returns Operation status
*/
lr20xx_status_t lr20xx_radio_common_set_pkt_type( const void* context, lr20xx_radio_common_pkt_type_t pkt_type );
/*!
* @brief Get the packet type currently in use
*
* @param [in] context Chip implementation context
* @param [out] pkt_type Packet type currently in use
*
* @returns Operation status
*/
lr20xx_status_t lr20xx_radio_common_get_pkt_type( const void* context, lr20xx_radio_common_pkt_type_t* pkt_type );
/*
* Configure when the Rx timeout timer stops:
* - false: on LoRa header / GFSK syncword detection
* - true: on preamble detection
/*!
* @brief Set the event on which the Rx timeout is stopped
*
* Depending on the configuration, Rx timeout is stopped either on the detection of the following events:
* - LoRa header detection (or Rx done in implicit mode) / GFSK syncword detection
* - Preamble detection
*
* @param [in] context Chip implementation context
* @param [in] is_stopped_on_preamble_detection If true, the timer stops on preamble detection
*
* @returns Operation status
*/
lr20xx_status_t lr20xx_radio_common_set_rx_timeout_stop_event( const void* context,
const bool is_stopped_on_preamble_detection );
/*!
* @brief Reset internal Rx stats
*
* @param [in] context Chip implementation context
*
* @returns Operation status
*/
lr20xx_status_t lr20xx_radio_common_reset_rx_stats( const void* context );
/*
* Get instantaneous RSSI during active reception.
* Full precision: RSSI_dBm = rssi_in_dbm - (half_dbm_count * 0.5); half_dbm_count may be NULL.
/*!
* @brief Get the instantaneous RSSI while the transceiver is in reception mode
*
* This command can be used during reception of a packet
*
* The instantaneous RSSI can be obtained with 0.5 dBm accuracy thanks to the output argument half_dbm_count, which is
* either 0 or 1, using the following formula:
*
* RSSI = rssi_in_dbm - ( half_dbm_count * 0.5 )
*
* The pointer half_dbm_count can be NULL, in which case the value is not returned.
*
* @param [in] context Chip implementation context
* @param [out] rssi_in_dbm Instantaneous RSSI.
* @param [out] half_dbm_count Count of 0.5 dBm to subtract to value in dBm. Can be NULL.
*
* @returns Operation status
*/
lr20xx_status_t lr20xx_radio_common_get_rssi_inst( const void* context, int16_t* rssi_in_dbm, uint8_t* half_dbm_count );
/*!
* @brief Start RX operations with a timeout in millisecond
*
* @remark To set the radio in Rx continuous mode, refer to @ref lr20xx_radio_common_set_rx_with_timeout_in_rtc_step
*
* @param [in] context Chip implementation context
* @param [in] timeout_in_ms Timeout configuration in millisecond for RX operation
*
* @returns Operation status
*/
lr20xx_status_t lr20xx_radio_common_set_rx( const void* context, const uint32_t timeout_in_ms );
/*
* Start RX with RTC step timeout. timeout_in_ms = steps / 32.768; max 0xFFFFFE (~511s).
* 0x000000 = single RX (wait for packet); 0xFFFFFF = continuous RX.
/*!
* @brief Start RX operations with a timeout in RTC step
*
* The timeout duration is obtained by:
* \f$ timeout\_duration\_ms = timeout\_in\_rtc\_step \times \frac{1}{32.768} \f$
*
* Maximal timeout value is 0xFFFFFE, which gives a maximal timeout of 511 seconds.
*
* The timeout argument can also have the following special values:
* <table>
* <tr><th> Special values </th><th> Meaning </th>
* <tr><td> 0x000000 </td><td> RX single - transceiver stays in RX mode until a packet is received </td>
* <tr><td> 0xFFFFFF </td><td> RX continuous - transceiver stays in RX mode even after reception of a packet </td>
* </table>
*
* @param [in] context Chip implementation context
* @param [in] timeout_in_rtc_step Timeout configuration in RTC step for RX operation
*
* @returns Operation status
*/
lr20xx_status_t lr20xx_radio_common_set_rx_with_timeout_in_rtc_step( const void* context,
const uint32_t timeout_in_rtc_step );
/* Start RX using timeout pre-configured by set_default_rx_tx_timeout[_in_rtc_step] */
/*!
* @brief Start RX operations with a pre-configured default timeout
*
* @remark The timeout has to be configured by calling either @ref lr20xx_radio_common_set_default_rx_tx_timeout or @ref
* lr20xx_radio_common_set_default_rx_tx_timeout_in_rtc_step
*
* @param [in] context Chip implementation context
*
* @returns Operation status
*/
lr20xx_status_t lr20xx_radio_common_set_rx_with_default_timeout( const void* context );
/*!
* @brief Start transmission operation with a timeout in millisecond
*
* @param [in] context Chip implementation context
* @param [in] timeout_in_ms Timeout configuration in millisecond for RX operation
*
* @returns Operation status
*/
lr20xx_status_t lr20xx_radio_common_set_tx( const void* context, const uint32_t timeout_in_ms );
/* Start TX with RTC step timeout. timeout=0 disables timeout. Max 0xFFFFFF (~511s). */
/*!
* @brief Start transmission operation with a timeout in RTC step
*
* The timeout duration is obtained by:
* \f$ timeout\_duration\_ms = timeout_in_rtc_step \times \frac{1}{32.768} \f$
*
* Maximal timeout value is 0xFFFFFF, which gives a maximal timeout of 511 seconds.
*
* If \p timeout_in_rtc_step is set to 0, then no timeout is used.
*
* @param [in] context Chip implementation context
* @param [in] timeout_in_rtc_step Timeout configuration in RTC step for TX operation
*
* @returns Operation status
*/
lr20xx_status_t lr20xx_radio_common_set_tx_with_timeout_in_rtc_step( const void* context,
const uint32_t timeout_in_rtc_step );
/* Start TX using timeout pre-configured by set_default_rx_tx_timeout[_in_rtc_step] */
/*!
* @brief Start TX operations with a pre-configured default timeout
*
* @remark The timeout has to be configured by calling either @ref lr20xx_radio_common_set_default_rx_tx_timeout or @ref
* lr20xx_radio_common_set_default_rx_tx_timeout_in_rtc_step
*
* @param [in] context Chip implementation context
*
* @returns Operation status
*/
lr20xx_status_t lr20xx_radio_common_set_tx_with_default_timeout( const void* context );
/*!
* @brief Set the transceiver into a Tx test mode.
*
* @param [in] context Chip implementation context
* @param [in] mode Test mode
*
* @returns Operation status
*/
lr20xx_status_t lr20xx_radio_common_set_tx_test_mode( const void* context, lr20xx_radio_common_tx_test_mode_t mode );
/* Select PA; set_pa_cfg must be called first */
/*!
* @brief Select the Power Amplifier to use
*
* @remark Configuration has to be applied first by calling @ref lr20xx_radio_common_set_pa_cfg
*
* @param [in] context Chip implementation context
* @param [in] sel Power amplifier selection
*
* @returns Operation status
*/
lr20xx_status_t lr20xx_radio_common_select_pa( const void* context, lr20xx_radio_common_pa_selection_t sel );
/* Converts ms to RTC steps and calls set_rx_duty_cycle_with_timing_in_rtc_step */
/*!
* @brief Configure and start a Rx Duty Cycle operation with timings in millisecond
*
* @remark This function computes timings in RTC step from values given in millisecond and then calls @ref
* lr20xx_radio_common_set_rx_duty_cycle_with_timing_in_rtc_step
*
* @param [in] context Chip implementation context
* @param [in] rx_period_in_ms Rx period in millisecond
* @param [in] sleep_period_in_ms Sleep period in millisecond
* @param [in] mode Operation mode used during Rx phase
*
* @returns Operation status
*/
lr20xx_status_t lr20xx_radio_common_set_rx_duty_cycle( const void* context, const uint32_t rx_period_in_ms,
const uint32_t sleep_period_in_ms,
const lr20xx_radio_common_rx_duty_cycle_mode_t mode );
/*
* Start RX duty cycle: Rx for rx_period, then sleep for sleep_period, repeat.
* On activity detected: extend Rx timeout to (2*rx_period + sleep_period).
* On packet received: return to fallback mode.
* CAD mode (LoRa only): configure CAD params before calling.
* To stop during sleep: call lr20xx_system_wakeup then lr20xx_system_set_standby_mode when BUSY goes low.
/*!
* @brief Configure and start a Rx Duty Cycle operation with timings in RTC step
*
* It executes the following steps:
* 1. Reception - enters reception state for duration defined by @p rx_period_in_rtc_step:
* - @p mode = LR20XX_RADIO_COMMON_RX_DUTY_CYCLE_MODE_RX: regular Rx mode
* - @p mode = LR20XX_RADIO_COMMON_RX_DUTY_CYCLE_MODE_CAD (LoRa only) : CAD mode
* 2. Depending on the over-the-air activity detection (either preamble detection or valid CAD):
* - In case of positive over-the-air detection, the Rx period timeout is restarted with the value
* \f$2 \times rx_period_in_rtc_step + sleep_period_in_rtc_step\f$
* - else, the transceiver goes into sleep mode with retention for a duration defined by @p
* sleep_period_in_rtc_step
* 3. On wake-up, the transceiver restarts the process to step 1
*
* The loop described above is terminated in the following cases:
* - a packet is received during a Rx window - the chip goes back to fallback mode configured with @ref
* lr20xx_radio_common_set_rx_tx_fallback_mode
* - a call to @ref lr20xx_system_set_standby_mode is done during a Rx window
* - a call to @ref lr20xx_system_wakeup is done during a sleep phase - to prevent a possible race condition from
* happening when the call is performed during the boot phase, it is recommended to call @ref
* lr20xx_system_set_standby_mode when BUSY is going low
*
* @remark If @p mode is set to @ref LR20XX_RADIO_COMMON_RX_DUTY_CYCLE_MODE_CAD, CAD parameters have to be defined
* before calling this function
*
* @param [in] context Chip implementation context
* @param [in] rx_period_in_rtc_step Rx period in RTC step
* @param [in] sleep_period_in_rtc_step Sleep period in RTC step
* @param [in] mode Operation mode used during Rx phase
*
* @returns Operation status
*/
lr20xx_status_t lr20xx_radio_common_set_rx_duty_cycle_with_timing_in_rtc_step(
const void* context, const uint32_t rx_period_in_rtc_step, const uint32_t sleep_period_in_rtc_step,
const lr20xx_radio_common_rx_duty_cycle_mode_t mode );
/*
* Configure automatic Tx-after-Rx or Rx-after-Tx.
* Set mode to Tx → auto-Rx fires; set mode to Rx → auto-Tx fires.
* Between operations the chip enters fallback mode. Triggers once then auto-disables.
* delay_in_tick must account for PA ramp, TCXO start, fallback mode switching.
* Pass condition=LR20XX_RADIO_COMMON_AUTO_TX_RX_OFF to disable.
/**
* @brief Configure the automatic Tx operation after Rx, or automatic Rx operation after Tx
*
* This feature allows the chip to automatically execute a Tx operation after an Rx one; or to automatically execute an
* Rx operation after a Tx one.
*
* The order of operation depends on the mode manually requested after issuing this command:
* - If the radio is set to Tx mode, then an automatic Rx will be executed;
* - If the radio is set to Rx mode, then an automatic Tx will be executed.
*
* This feature is similar to a call to @ref lr20xx_radio_common_set_tx_with_timeout_in_rtc_step (or @ref
* lr20xx_radio_common_set_rx_with_timeout_in_rtc_step) after the given delay_in_tick. Therefore to fine tune the
* instant of first bit automatically sent over-the-air (or reception window opening) other delays have to be taken into
* account when determining the delay_in_tick value. For instance, but not limited to:
* - PA ramp-up
* - TCXO start time (if applicable)
* - Configured fallback mode
* - Radio state switching time
*
* When the automatic Tx/Rx is enabled, the chip is in the state configured by @ref
* lr20xx_radio_common_set_rx_tx_fallback_mode between the end of Rx (or Tx) operation and the start of the next
* automatic Tx (or Rx) operation.
*
* Calling @ref lr20xx_radio_common_configure_auto_tx_rx with condition being @ref LR20XX_RADIO_COMMON_AUTO_TX_RX_OFF
* disables the automatic Tx or Rx behavior. Doing so after end of Rx (or Tx) operation and start of automatic Tx (or
* Rx) also cancels the automatic Tx or Rx operation.
*
* Once the automatic operation triggers, the feature is automatically disabled. So that to engage again an automatic
* operation after a manual one, the @ref lr20xx_radio_common_configure_auto_tx_rx must be called to enable it again.
*
* @param context Chip implementation context
* @param configuration The configuration of the automatic Tx/Rx
*
* @see lr20xx_radio_common_set_tx_with_timeout_in_rtc_step, lr20xx_radio_common_set_rx_with_timeout_in_rtc_step,
* lr20xx_radio_common_set_rx_tx_fallback_mode
*
* @return lr20xx_status_t
*/
lr20xx_status_t lr20xx_radio_common_configure_auto_tx_rx(
const void* context, const lr20xx_radio_common_auto_tx_rx_configuration_t* configuration );
/*!
* @brief Get the length in byte of the last received packet
*
* @param [in] context Chip implementation context
* @param [out] pkt_len Length in byte of the last received packet
*
* @returns Operation status
*/
lr20xx_status_t lr20xx_radio_common_get_rx_packet_length( const void* context, uint16_t* pkt_len );
/*!
* @brief Set default timeout values for RX and TX operations
*
* @param [in] context Chip implementation context
* @param [in] rx_timeout_in_ms Timeout configuration in millisecond for RX operation
* @param [in] tx_timeout_in_ms Timeout configuration in millisecond for TX operation
*
* @returns Operation status
*/
lr20xx_status_t lr20xx_radio_common_set_default_rx_tx_timeout( const void* context, uint32_t rx_timeout_in_ms,
uint32_t tx_timeout_in_ms );
/* Same special values apply as for set_rx/tx_with_timeout_in_rtc_step */
/*!
* @brief Set default timeout values for RX and TX operations
*
* @remark Special values defined for @ref lr20xx_radio_common_set_rx_with_timeout_in_rtc_step and @ref
* lr20xx_radio_common_set_tx_with_timeout_in_rtc_step are also applicable here
*
* @param [in] context Chip implementation context
* @param [in] rx_timeout_in_rtc_step Timeout configuration in RTC step for RX operation
* @param [in] tx_timeout_in_rtc_step Timeout configuration in RTC step for TX operation
*
* @returns Operation status
*/
lr20xx_status_t lr20xx_radio_common_set_default_rx_tx_timeout_in_rtc_step( const void* context,
uint32_t rx_timeout_in_rtc_step,
uint32_t tx_timeout_in_rtc_step );
/* Arm a 32MHz timestamp on the given radio event; read with get_elapsed_time_in_tick */
/*!
* @brief Set a timestamp source for a given configuration slot
*
* @remark This command configure a source linked to a radio event that will then be used by @ref
* lr20xx_radio_common_get_elapsed_time_in_tick to compute the elapsed time
*
* @param [in] context Chip implementation context
* @param [in] cfg_slot Configuration slot
* @param [in] source Timestamp source
*
* @returns Operation status
*/
lr20xx_status_t lr20xx_radio_common_set_timestamp_source( const void* context,
lr20xx_radio_common_timestamp_cfg_slot_t cfg_slot,
lr20xx_radio_common_timestamp_source_t source );
/*
* Read elapsed 32MHz ticks since the event configured in set_timestamp_source for cfg_slot.
* Radio must not have entered sleep between the event and this call.
/*!
* @brief Get the elapsed time since radio event registered at given configuration slot
*
* @remark This is the time elapsed between the event configured with @ref lr20xx_radio_common_set_timestamp_source and
* the NSS falling edge of this request
*
* @remark That radio must not be put in sleep mode between the configured event and the call to this function
*
* @param [in] context Chip implementation context
* @param [in] cfg_slot Configuration slot
* @param [out] elapsed_time_in_tick Elapsed time in 32MHz tick
*
* @returns Operation status
*/
lr20xx_status_t lr20xx_radio_common_get_elapsed_time_in_tick( const void* context,
lr20xx_radio_common_timestamp_cfg_slot_t cfg_slot,
uint32_t* elapsed_time_in_tick );
/* Start CCA (Clear Channel Assessment); duration in 32MHz steps */
/*!
* @brief Launch a CCA (Clear Channel Assessment) operation
*
* @param [in] context Chip implementation context
* @param [in] duration CCA duration in 32MHz step
*
* @returns Operation status
*/
lr20xx_status_t lr20xx_radio_common_set_cca( const void* context, const uint32_t duration );
/*!
* @brief Get the CCA values once the operation is over
*
* @param [in] context Chip implementation context
* @param [out] cca_res Structure holding CCA result
*
* @returns Operation status
*/
lr20xx_status_t lr20xx_radio_common_get_cca_result( const void* context, lr20xx_radio_common_cca_res_t* cca_res );
/*!
* @brief Set the gain to be used by the AGC (Automatic Gain Control)
*
* @param [in] context Chip implementation context
* @param [in] gain Gain
*
* @returns Operation status
*/
lr20xx_status_t lr20xx_radio_common_set_agc_gain( const void* context, lr20xx_radio_common_gain_step_t gain );
/* Set non-LoRa CAD parameters; not applicable when packet type is LoRa */
/*!
* @brief Set non-LoRa CAD parameters
*
* @remark This command is not applicable if the packet type is set to LoRa
*
* @param [in] context Chip implementation context
* @param [in] params CAD parameters
*
* @returns Operation status
*/
lr20xx_status_t lr20xx_radio_common_set_cad_params( const void* context,
const lr20xx_radio_common_cad_params_t* params );
/*!
* @brief Set the chip in non-LoRa CAD mode
*
* @param [in] context Chip implementation context
*
* @returns Operation status
*/
lr20xx_status_t lr20xx_radio_common_set_cad( const void* context );
/*
* Get LQI of last detected packet. Valid from preamble detection until next Rx call.
* Applies to FSK-based modes: FSK, BLE, OQPSK-15.4, Wi-SUN, Wireless M-Bus, Z-Wave.
/**
* @brief Get the Link Quality Indicator (LQI) of latest detected packet
*
* This function is only valid if the latest received packet is an FSK based modulation:
* - FSK
* - Bluetooth_LE
* - OQPSK 15.4
* - Wi-SUN
* - Wireless M-Bus
* - Z-Wave
*
* The value returned corresponds to the latest detected packet. It is valid from the packet detection (corresponding to
* @ref LR20XX_SYSTEM_IRQ_PREAMBLE_DETECTED raised if enabled) until next Rx attempt (through call to @ref
* lr20xx_radio_common_set_rx or @ref lr20xx_radio_common_set_rx_with_timeout_in_rtc_step for instance).
*
* @param[in] context Chip implementation context
* @param[out] lqi The LQI value
* @return lr20xx_status_t Operation status
*/
lr20xx_status_t lr20xx_radio_common_get_lqi( const void* context, lr20xx_radio_common_lqi_value_t* lqi );
@@ -39,12 +39,19 @@
#include "lr20xx_radio_fifo.h"
#include "lr20xx_hal.h"
#include "lr20xx_regmem.h"
#include "lr20xx_system.h"
/*
* -----------------------------------------------------------------------------
* --- PRIVATE MACROS-----------------------------------------------------------
*/
#define LR20XX_RADIO_FIFO_TX_FIFO_ADDRESS ( 0x00F3002C )
#define LR20XX_RADIO_FIFO_TX_FIFO_SIZE_ADDRESS ( 0x00F30034 )
#define LR20XX_RADIO_FIFO_RX_FIFO_ADDRESS ( 0x00F30028 )
#define LR20XX_RADIO_FIFO_RX_FIFO_SIZE_ADDRESS ( 0x00F30030 )
/*
* -----------------------------------------------------------------------------
* --- PRIVATE CONSTANTS -------------------------------------------------------
@@ -257,6 +264,52 @@ lr20xx_status_t lr20xx_radio_fifo_get_and_clear_irq_flags( const void* context,
return status;
}
lr20xx_status_t lr20xx_radio_fifo_configure_1024_byte_tx_fifo( const void* context )
{
const uint32_t tx_fifo_1024_memory_address = 0x00804000;
RETURN_STATUS_ON_NOT_OK(
lr20xx_regmem_write_regmem32( context, LR20XX_RADIO_FIFO_TX_FIFO_ADDRESS, &tx_fifo_1024_memory_address, 1 ) );
const uint32_t tx_fifo_size = 0x000003FC;
return lr20xx_regmem_write_regmem32( context, LR20XX_RADIO_FIFO_TX_FIFO_SIZE_ADDRESS, &tx_fifo_size, 1 );
}
lr20xx_status_t lr20xx_radio_fifo_1024_byte_tx_fifo_store_retention_mem( const void* context,
uint8_t retention_slot_address,
uint8_t retention_slot_size )
{
// Store the registers configuration for the TX FIFOs location in retention
RETURN_STATUS_ON_NOT_OK( lr20xx_system_add_register_to_retention_mem( context, retention_slot_address,
LR20XX_RADIO_FIFO_TX_FIFO_ADDRESS ) );
// Store the registers configuration for the TX FIFOs size in retention
return lr20xx_system_add_register_to_retention_mem( context, retention_slot_size,
LR20XX_RADIO_FIFO_TX_FIFO_SIZE_ADDRESS );
}
lr20xx_status_t lr20xx_radio_fifo_configure_1024_byte_rx_fifo( const void* context )
{
const uint32_t rx_fifo_1024_memory_address = 0x00804400;
RETURN_STATUS_ON_NOT_OK(
lr20xx_regmem_write_regmem32( context, LR20XX_RADIO_FIFO_RX_FIFO_ADDRESS, &rx_fifo_1024_memory_address, 1 ) );
const uint32_t rx_fifo_size = 0x000003E8;
return lr20xx_regmem_write_regmem32( context, LR20XX_RADIO_FIFO_RX_FIFO_SIZE_ADDRESS, &rx_fifo_size, 1 );
}
lr20xx_status_t lr20xx_radio_fifo_1024_byte_rx_fifo_store_retention_mem( const void* context,
uint8_t retention_slot_address,
uint8_t retention_slot_size )
{
// Store the registers configuration for the RX FIFOs location in retention
RETURN_STATUS_ON_NOT_OK( lr20xx_system_add_register_to_retention_mem( context, retention_slot_address,
LR20XX_RADIO_FIFO_RX_FIFO_ADDRESS ) );
// Store the registers configuration for the RX FIFOs size in retention
return lr20xx_system_add_register_to_retention_mem( context, retention_slot_size,
LR20XX_RADIO_FIFO_RX_FIFO_SIZE_ADDRESS );
}
/*
* -----------------------------------------------------------------------------
* --- PRIVATE FUNCTIONS DEFINITION --------------------------------------------
@@ -68,33 +68,216 @@ extern "C" {
* --- PUBLIC FUNCTIONS PROTOTYPES ---------------------------------------------
*/
/*!
* @brief Read data from RX First in First out (FiFo) radio memory
*
* The RX FiFo radio memory contains packet received or being received.
*
* @param [in] context Chip implementation context
* @param [in] buffer The buffer to be filled with data read from RX FiFo. It is up to the caller to ensure it is at
* least @p length bytes long.
* @param [in] length The number of bytes to read from RX FiFo
*
* @returns Operation status
*
* @see lr20xx_radio_fifo_write_tx
*/
lr20xx_status_t lr20xx_radio_fifo_read_rx( const void* context, uint8_t* buffer, const uint16_t length );
/*!
* @brief Write data to TX First in First out (FiFo) radio memory
*
* The TX FiFo radio memory contains packet to send.
*
* @param [in] context Chip implementation context
* @param [in] buffer The buffer to be written to TX FiFo. It is up to the caller to ensure it is at least
* @p length bytes long.
* @param [in] length The number of bytes to write to TX FiFo
*
* @returns Operation status
*
* @see lr20xx_radio_fifo_read_rx
*/
lr20xx_status_t lr20xx_radio_fifo_write_tx( const void* context, const uint8_t* buffer, const uint16_t length );
/*!
* @brief Clear Rx FIFO
*
* @param [in] context Chip implementation context
*
* @returns Operation status
*/
lr20xx_status_t lr20xx_radio_fifo_clear_rx( const void* context );
/*!
* @brief Clear Tx FIFO
*
* @param [in] context Chip implementation context
*
* @returns Operation status
*/
lr20xx_status_t lr20xx_radio_fifo_clear_tx( const void* context );
/*!
* @brief Get Rx FIFO level
*
* @param [in] context Chip implementation context
* @param [out] fifo_level Rx FIFO level in byte
*
* @returns Operation status
*/
lr20xx_status_t lr20xx_radio_fifo_get_rx_level( const void* context, uint16_t* fifo_level );
/*!
* @brief Get Tx FIFO level
*
* @param [in] context Chip implementation context
* @param [out] fifo_level Tx FIFO level in byte
*
* @returns Operation status
*/
lr20xx_status_t lr20xx_radio_fifo_get_tx_level( const void* context, uint16_t* fifo_level );
/*
* Configure FIFO threshold IRQs. Threshold IRQs fire on level crossing in the triggering direction;
* clearing the IRQ flag does not re-fire until the threshold is crossed again.
* rx_fifo_high_threshold: triggers THRESHOLD_HIGH when Rx level rises above this
* rx_fifo_low_threshold: triggers THRESHOLD_LOW when Rx level falls below this
* tx_fifo_high_threshold: triggers THRESHOLD_HIGH when Tx level rises above this
* tx_fifo_low_threshold: triggers THRESHOLD_LOW when Tx level falls below this
/*!
* @brief Configure FIFO events and threshold levels triggering a FIFO interrupt in Rx and Tx
*
* @remark When configured, the FIFO interrupts are triggered if the FIFO level crosses the threshold in the correct
* direction. Therefore if a threshold related IRQ is cleared, it will be raised again only if the FIFO level crosses
* the threshold on the correct direction.
*
* @param [in] context Chip implementation context
* @param [in] rx_fifo_irq_enable FIFO events triggering an interrupt in Rx
* @param [in] tx_fifo_irq_enable FIFO events triggering an interrupt in Tx
* @param [in] rx_fifo_high_threshold Rx FIFO threshold above which an interrupt (if
* LR20XX_RADIO_FIFO_FLAG_THRESHOLD_HIGH is enabled) is triggered
* @param [in] tx_fifo_low_threshold Tx FIFO threshold below which an interrupt (if
* LR20XX_RADIO_FIFO_FLAG_THRESHOLD_LOW is enabled) is triggered
* @param [in] rx_fifo_low_threshold Rx FIFO threshold below which an interrupt (if
* LR20XX_RADIO_FIFO_FLAG_THRESHOLD_LOW is enabled) is triggered
* @param [in] tx_fifo_high_threshold Tx FIFO threshold above which an interrupt (if
* LR20XX_RADIO_FIFO_FLAG_THRESHOLD_HIGH is enabled) is triggered
*
* @returns Operation status
*/
lr20xx_status_t lr20xx_radio_fifo_cfg_irq( const void* context, lr20xx_radio_fifo_flag_t rx_fifo_irq_enable,
lr20xx_radio_fifo_flag_t tx_fifo_irq_enable, uint16_t rx_fifo_high_threshold,
uint16_t tx_fifo_low_threshold, uint16_t rx_fifo_low_threshold,
uint16_t tx_fifo_high_threshold );
/*!
* @brief Clear specific IRQ flags for both Rx and Tx FIFO
*
* @param [in] context Chip implementation context
* @param [in] rx_fifo_flags_to_clear Rx FIFO IRQ flags to clear
* @param [in] tx_fifo_flags_to_clear Tx FIFO IRQ flags to clear
*
* @returns Operation status
*/
lr20xx_status_t lr20xx_radio_fifo_clear_irq_flags( const void* context, lr20xx_radio_fifo_flag_t rx_fifo_flags_to_clear,
lr20xx_radio_fifo_flag_t tx_fifo_flags_to_clear );
/*!
* @brief Get FIFO events triggering a FIFO interrupt in Rx and Tx
*
* @param [in] context Chip implementation context
* @param [out] rx_fifo_flags FIFO events triggering an interrupt in Rx
* @param [out] tx_fifo_flags FIFO events triggering an interrupt in Tx
*
* @returns Operation status
*/
lr20xx_status_t lr20xx_radio_fifo_get_irq( const void* context, lr20xx_radio_fifo_flag_t* rx_fifo_flags,
lr20xx_radio_fifo_flag_t* tx_fifo_flags );
/*!
* @brief Clear and return FiFo IRQ flags
*
* @param [in] context Chip implementation context
* @param [out] rx_fifo_flags Rx FiFo flags
* @param [out] tx_fifo_flags Tx FiFo flags
*
* @returns Operation status
*/
lr20xx_status_t lr20xx_radio_fifo_get_and_clear_irq_flags( const void* context, lr20xx_radio_fifo_flag_t* rx_fifo_flags,
lr20xx_radio_fifo_flag_t* tx_fifo_flags );
/**
* @brief Switch Tx FiFo to 1024-bytes FiFo
*
* This command switches the Tx FiFo from default 256-byte Tx FiFo to extended 1024-byte Tx FiFo.
*
* It modifies internal registers that are not maintained during sleep mode.
* Refer to the function @ref lr20xx_radio_fifo_1024_byte_tx_fifo_store_retention_mem configures to configure the radio
* so that it maintains the registers.
*
* Usage of 1024-byte Tx FiFo comes with a limitation when configuring the low thresholds IRQ with @ref
* lr20xx_radio_fifo_cfg_irq.
* Refer to @ref lr20xx_workarounds_1024_byte_fifo_cfg_irq for a workaround of this limitation.
*
* @param [in] context Chip implementation context
* @param [in] retention_slot_address Retention memory slot to store Tx FiFo address
* @param [in] retention_slot_size Retention memory slot to store Tx FiFo size
*
* @return Operation status
*
* @see lr20xx_radio_fifo_1024_byte_tx_fifo_store_retention_mem, lr20xx_radio_fifo_configure_1024_byte_rx_fifo,
* lr20xx_workarounds_1024_byte_fifo_cfg_irq
*/
lr20xx_status_t lr20xx_radio_fifo_configure_1024_byte_tx_fifo( const void* context );
/**
* @brief Store the registers to configure the 1024 bytes Tx FiFo in retention memory
*
* @param [in] context Chip implementation context
* @param [in] retention_slot_address Retention memory slot to store Tx FiFo address
* @param [in] retention_slot_size Retention memory slot to store Tx FiFo size
*
* @return Operation status
*
* @see lr20xx_system_add_register_to_retention_mem, lr20xx_radio_fifo_configure_1024_byte_tx_fifo
*/
lr20xx_status_t lr20xx_radio_fifo_1024_byte_tx_fifo_store_retention_mem( const void* context,
uint8_t retention_slot_address,
uint8_t retention_slot_size );
/**
* @brief Switch Rx FiFo to 1024-bytes FiFo
*
* This command switches the Rx FiFo from default 256-byte Rx FiFo to extended 1024-byte Rx FiFo.
*
* It modifies internal registers that are not maintained during sleep mode.
* Refer to the function @ref lr20xx_radio_fifo_1024_byte_rx_fifo_store_retention_mem configures to configure the radio
* so that it maintains the registers.
*
* Usage of 1024-byte Rx FiFo comes with a limitation when configuring the low thresholds IRQ with @ref
* lr20xx_radio_fifo_cfg_irq.
* Refer to @ref lr20xx_workarounds_1024_byte_fifo_cfg_irq for a workaround of this limitation.
*
* @param [in] context Chip implementation context
* @param [in] retention_slot_address Retention memory slot to store Rx FiFo address
* @param [in] retention_slot_size Retention memory slot to store Rx FiFo size
*
* @return Operation status
*
* @see lr20xx_radio_fifo_1024_byte_rx_fifo_store_retention_mem,
* lr20xx_radio_fifo_configure_1024_byte_tx_fifo,lr20xx_workarounds_1024_byte_fifo_cfg_irq
*/
lr20xx_status_t lr20xx_radio_fifo_configure_1024_byte_rx_fifo( const void* context );
/**
* @brief Store the registers to configure the 1024 bytes Rx FiFo in retention memory
*
* @param [in] context Chip implementation context
* @param [in] retention_slot_address Retention memory slot to store Rx FiFo address
* @param [in] retention_slot_size Retention memory slot to store Rx FiFo size
*
* @return Operation status
*
* @see lr20xx_system_add_register_to_retention_mem, lr20xx_radio_fifo_configure_1024_byte_rx_fifo
*/
lr20xx_status_t lr20xx_radio_fifo_1024_byte_rx_fifo_store_retention_mem( const void* context,
uint8_t retention_slot_address,
uint8_t retention_slot_size );
#ifdef __cplusplus
}
#endif
@@ -68,39 +68,124 @@ extern "C" {
* --- PUBLIC FUNCTIONS PROTOTYPES ---------------------------------------------
*/
/*
* Set FLRC modulation params. Not available on LR2022.
* Applies lr20xx_workarounds_dcdc_configure automatically unless LR20XX_WORKAROUNDS_DISABLE_AUTOMATIC_DCDC_CONFIGURE.
/**
* @brief Set the modulation parameters for FLRC packets
*
* @note This command is not available to LR2022
*
* @param[in] context Chip implementation context
* @param[in] params Structure of FLRC modulation configuration
*
* @return lr20xx_status_t Operation status
*/
lr20xx_status_t lr20xx_radio_flrc_set_modulation_params( const void* context,
const lr20xx_radio_flrc_mod_params_t* params );
/* Set FLRC packet params. Not available on LR2022. */
/**
* @brief Set the packet parameters for FLRC packets
*
* @note This command is not available to LR2022
*
* @param[in] context Chip implementation context
* @param[in] params Structure of FLRC packet configuration
*
* @return lr20xx_status_t Operation status
*/
lr20xx_status_t lr20xx_radio_flrc_set_pkt_params( const void* context, const lr20xx_radio_flrc_pkt_params_t* params );
/*
* Get FLRC Rx statistics. Not available on LR2022.
* Stats reset on POR, retention-less sleep, or lr20xx_radio_common_reset_rx_stats.
/**
* @brief Get the internal statistics of received FLRC packets
*
* The internal statistics are reset on:
* - Power On Reset (POR)
* - sleep without memory retention
* - call to lr20xx_radio_common_reset_rx_stats
*
* @note This command is not available to LR2022
*
* @param[in] context Chip implementation context
* @param[out] statistics FLRC received packet statistics
*
* @return lr20xx_status_t Operation status
*
* @see lr20xx_radio_common_reset_rx_stats
*/
lr20xx_status_t lr20xx_radio_flrc_get_rx_stats( const void* context, lr20xx_radio_flrc_rx_stats_t* statistics );
/*
* Get status of last FLRC received packet. Not available on LR2022.
* rssi_sync/syncword_index available from SYNC_WORD_HEADER_VALID IRQ.
* rssi_avg available from RX_DONE IRQ.
/**
* @brief Get the status of the last FLRC received packet
*
* Availability of the packet status fields depend on the IRQ as follows:
* - Available from LR20XX_SYSTEM_IRQ_SYNC_WORD_HEADER_VALID:
* - lr20xx_radio_flrc_pkt_status_t.rssi_sync_in_dbm
* - lr20xx_radio_flrc_pkt_status_t.rssi_sync_half_dbm_count
* - lr20xx_radio_flrc_pkt_status_t.syncword_index
* - Available from LR20XX_SYSTEM_IRQ_RX_DONE:
* - lr20xx_radio_flrc_pkt_status_t.rssi_avg_in_dbm
* - lr20xx_radio_flrc_pkt_status_t.rssi_avg_half_dbm_count
*
* @note This command is not available to LR2022
*
* @param[in] context Chip implementation context
* @param[out] pkt_status FLRC packet status structure
*
* @return lr20xx_status_t Operation status
*/
lr20xx_status_t lr20xx_radio_flrc_get_pkt_status( const void* context, lr20xx_radio_flrc_pkt_status_t* pkt_status );
/* Set 2-byte short syncword at syncword_index. Not available on LR2022. */
/**
* @brief Set a short syncword for FLRC packet
*
* A short syncword is a 2-bytes long syncword.
*
* Status is available only after the end of a packet reception.
*
* @note This command is not available to LR2022
*
* @param[in] context Chip implementation context
* @param[in] syncword_index Syncword index to be configured
* @param[in] short_syncword Syncword value to be configured. It is up to the caller to ensure @p short_syncword is at
* least @ref LR20XX_RADIO_FLRC_SHORT_SYNCWORD_LENGTH bytes long
*
* @return lr20xx_status_t Operation status
*
* @see lr20xx_radio_flrc_set_syncword
*/
lr20xx_status_t lr20xx_radio_flrc_set_short_syncword(
const void* context, uint8_t syncword_index,
const uint8_t short_syncword[LR20XX_RADIO_FLRC_SHORT_SYNCWORD_LENGTH] );
/* Set 4-byte syncword at syncword_index. Not available on LR2022. */
/**
* @brief Set the syncword for FLRC packet
*
* Status is available only after the end of a packet reception.
*
* @note This command is not available to LR2022
*
* @param[in] context Chip implementation context
* @param[in] syncword_index Syncword index to be configured
* @param[in] syncword Syncword value to be configured. It is up to the caller to ensure @p short_syncword is at least
* @ref LR20XX_RADIO_FLRC_SYNCWORD_LENGTH bytes long
*
* @return lr20xx_status_t Operation status
*
* @see lr20xx_radio_flrc_set_short_syncword
*/
lr20xx_status_t lr20xx_radio_flrc_set_syncword( const void* context, uint8_t syncword_index,
const uint8_t syncword[LR20XX_RADIO_FLRC_SYNCWORD_LENGTH] );
/* Compute FLRC time-on-air in microseconds. Not available on LR2022. */
/**
* @brief Helper function to get the time-on-air of FLRC packet, in microseconds
*
* @note This command is not available to LR2022
*
* @param pkt_params The packet parameter configuration
* @param mod_params The modulation parameter configuration
*
* @return Time-on-air of the packet in microsecond
*
* @see lr20xx_radio_flrc_set_modulation_params, lr20xx_radio_flrc_set_pkt_params
*/
uint32_t lr20xx_get_flrc_time_on_air_in_us( const lr20xx_radio_flrc_pkt_params_t* pkt_params,
const lr20xx_radio_flrc_mod_params_t* mod_params );
@@ -51,10 +51,16 @@ extern "C" {
* --- PUBLIC MACROS -----------------------------------------------------------
*/
/*! @brief FLRC short syncword length in bytes */
/**
* @brief Length in bytes of the FLRC short syncword
*
*/
#define LR20XX_RADIO_FLRC_SHORT_SYNCWORD_LENGTH ( 2 )
/*! @brief FLRC syncword length in bytes */
/**
* @brief Length in bytes of the FLRC syncword
*
*/
#define LR20XX_RADIO_FLRC_SYNCWORD_LENGTH ( 4 )
/*
@@ -179,8 +185,9 @@ typedef enum lr20xx_radio_flrc_crc_types_e
LR20XX_RADIO_FLRC_CRC_4_BYTES = 0x03,
} lr20xx_radio_flrc_crc_types_t;
/*!
* @brief Modulation configuration for FLRC packet
/**
* @brief Modulation configuration for LoRa packet
*
*/
typedef struct lr20xx_radio_flrc_mod_params_s
{
@@ -214,6 +221,7 @@ typedef struct lr20xx_radio_flrc_rx_stats_s
uint16_t received_packets; //!< Number of received packets
uint16_t crc_errors; //!< Number of received packets with CRC error
uint16_t length_errors; //!< Number of received packets with length error
uint16_t crc_ok; //!< Number of received packets with CRC ok
} lr20xx_radio_flrc_rx_stats_t;
/**
@@ -47,7 +47,10 @@
* --- PRIVATE MACROS-----------------------------------------------------------
*/
#define LR20XX_RADIO_LORA_CAD_SIDE_DETECTOR_CONFIGURATION_LENGTH ( 2u ) /* pnr_delta + det_peak */
/**
* @brief Length in byte of one side detector CAD configuration
*/
#define LR20XX_RADIO_LORA_CAD_SIDE_DETECTOR_CONFIGURATION_LENGTH ( 2u )
#define LR20XX_RADIO_LORA_SET_SIDE_DETECTOR_CONFIGURE_CAD_CMD_LENGTH ( 2 )
#define LR20XX_RADIO_LORA_SET_MODULATION_PARAMS_CMD_LENGTH ( 2 + 2 )
@@ -66,8 +69,8 @@
#define LR20XX_RADIO_LORA_CONFIGURE_SIDE_DETECTOR_CAD_TEMP_LENGTH \
( 3 * LR20XX_RADIO_LORA_CAD_SIDE_DETECTOR_CONFIGURATION_LENGTH )
#define LR20XX_RADIO_LORA_GET_RX_STATISTICS_RBUFFER_LENGTH ( 8 )
#define LR20XX_RADIO_LORA_GET_PACKET_STATUS_RBUFFER_LENGTH ( 6 )
#define LR20XX_RADIO_LORA_GET_RX_STATISTICS_RBUFFER_LENGTH ( 10 )
#define LR20XX_RADIO_LORA_GET_PACKET_STATUS_RBUFFER_LENGTH ( 9 )
/*
* -----------------------------------------------------------------------------
@@ -79,7 +82,9 @@
* --- PRIVATE TYPES -----------------------------------------------------------
*/
/* LoRa radio command opcodes */
/*!
* @brief Operating codes for radio related operations
*/
enum
{
LR20XX_RADIO_LORA_SET_SIDE_DETECTOR_CONFIGURE_CAD_OC = 0x021E,
@@ -113,11 +118,34 @@ typedef enum
* --- PRIVATE FUNCTIONS DECLARATION -------------------------------------------
*/
/* Send SET_LORA_SEARCH_SYMBOLS command with given n_symbols value and format byte */
/**
* @brief Helper function that abstract the call for lr20xx_radio_lora_set_lora_search_symbols_by_number and
* lr20xx_radio_lora_set_lora_search_symbols_by_mantissa
*
* @param[in] context Chip implementation context
* @param[in] n_symbols A byte representing the number of symbol. Meaning depends on format
* @param[in] format The format that defines the meaning of n_symbols
* @return lr20xx_status_t
*/
static lr20xx_status_t abstract_search_symbols( const void* context, uint8_t n_symbols, search_symbol_format_t format );
/* Read 2 bytes MSB-first from buffer into uint16_t */
/**
* @brief Read two bytes from buffer and convert it in 16 bits value MSB first
*
* @param buffer Pointer to location where to read 2 bytes. It is up to the caller to ensure there are at least two
* bytes to read
*
* @return The MSB first value corresponding to the consecutive bytes read
*/
static uint16_t read_2_bytes_msbf( const uint8_t* buffer );
/* Pack lr20xx_radio_lora_side_detector_cfg_t into a single command byte: sf[7:4] | ppm[3:2] | iq[1:0] */
/**
* @brief Compute the byte representation of LoRa side detector configuration
*
* @param side_detector_cfg The LoRa side detector configuration
*
* @return uint8_t The byte representing the LoRa side detector configuration
*/
static uint8_t radio_lora_side_detector_cfg_to_byte( const lr20xx_radio_lora_side_detector_cfg_t* side_detector_cfg );
/*
@@ -163,17 +191,8 @@ lr20xx_status_t lr20xx_radio_lora_set_modulation_params( const void*
( uint8_t ) ( ( mod_params->cr << 4 ) + mod_params->ppm ),
};
const lr20xx_status_t write_status = ( lr20xx_status_t ) lr20xx_hal_write(
context, cbuffer, LR20XX_RADIO_LORA_SET_MODULATION_PARAMS_CMD_LENGTH, 0, 0 );
if( write_status != LR20XX_STATUS_OK )
{
return write_status;
}
else
{
return LR20XX_WORKAROUNDS_CONDITIONAL_APPLY_AUTOMATIC_DCDC_CONFIGURE( context );
}
return ( lr20xx_status_t ) lr20xx_hal_write( context, cbuffer, LR20XX_RADIO_LORA_SET_MODULATION_PARAMS_CMD_LENGTH,
0, 0 );
}
lr20xx_status_t lr20xx_radio_lora_set_packet_params( const void* context,
@@ -324,7 +343,8 @@ lr20xx_status_t lr20xx_radio_lora_get_rx_statistics( const void*
statistics->n_received_packets = read_2_bytes_msbf( rbuffer + 0 );
statistics->n_crc_errors = read_2_bytes_msbf( rbuffer + 2 );
statistics->n_header_errors = read_2_bytes_msbf( rbuffer + 4 );
statistics->n_false_synchronisation = read_2_bytes_msbf( rbuffer + 6 );
statistics->n_header_valid = read_2_bytes_msbf( rbuffer + 6 );
statistics->n_false_synchronisation = read_2_bytes_msbf( rbuffer + 8 );
}
return status;
@@ -355,6 +375,10 @@ lr20xx_status_t lr20xx_radio_lora_get_packet_status( const void*
pkt_status->detector = ( rbuffer[5] >> 2 ) & 0x0F;
pkt_status->rssi_pkt_half_dbm_count = ( rbuffer[5] >> 1 ) & 0x01;
pkt_status->rssi_signal_pkt_half_dbm_count = ( rbuffer[5] >> 0 ) & 0x01;
/* Extract 24-bit signed value and sign-extend to 32 bits */
int32_t freq_offset_24 = ( ( rbuffer[6] << 16 ) | ( rbuffer[7] << 8 ) | rbuffer[8] ) & 0x00FFFFFF;
/* Sign-extend: shift left 8 bits then arithmetic shift right 8 bits */
pkt_status->freq_offset_hz = ( freq_offset_24 << 8 ) >> 8;
}
return status;
@@ -535,20 +559,24 @@ uint32_t lr20xx_radio_lora_get_time_on_air_in_ms( const lr20xx_radio_lora_pkt_pa
{
uint32_t numerator = 1000U * lr20xx_radio_lora_get_time_on_air_numerator( pkt_p, mod_p );
uint32_t denominator = lr20xx_radio_lora_get_bw_in_hz( mod_p->bw );
// Perform integral ceil()
return ( numerator + denominator - 1 ) / denominator;
}
lr20xx_radio_lora_ppm_t lr20xx_radio_lora_get_recommended_ppm_offset( lr20xx_radio_lora_sf_t sf,
lr20xx_radio_lora_bw_t bw )
{
// PPM offset is LR20XX_RADIO_LORA_PPM_1_4, except for the cases that follow
lr20xx_radio_lora_ppm_t ppm_offset = LR20XX_RADIO_LORA_PPM_1_4;
if( ( sf != LR20XX_RADIO_LORA_SF11 ) && ( sf != LR20XX_RADIO_LORA_SF12 ) )
{
// 1. If sf is not SF11 nor SF12: no ppm offset
ppm_offset = LR20XX_RADIO_LORA_NO_PPM;
}
else
{
// 2. Else it depends on the bandwidth
switch( bw )
{
case LR20XX_RADIO_LORA_BW_1000:
@@ -68,113 +68,402 @@ extern "C" {
* --- PUBLIC FUNCTIONS PROTOTYPES ---------------------------------------------
*/
/*
* Set LoRa modulation params. Applies lr20xx_workarounds_dcdc_configure automatically unless
* LR20XX_WORKAROUNDS_DISABLE_AUTOMATIC_DCDC_CONFIGURE. For RTToF with fractional BW, also call
* lr20xx_workarounds_rttof_results_deviation. See lr20xx_radio_lora_get_recommended_ppm_offset for PPM offset.
/**
* @brief Set the modulation parameters for LoRa packets
*
* @param[in] context Chip implementation context
* @param[in] mod_params Structure of LoRa modulation configuration
*
* @note For RTToF operations with fractional bandwidth, the workaround @ref lr20xx_workarounds_rttof_results_deviation
* shall be applied. Refer to its documentation for details.
*
* @return lr20xx_status_t Operation status
*
* @see lr20xx_radio_lora_get_recommended_ppm_offset, lr20xx_workarounds_rttof_results_deviation
*/
lr20xx_status_t lr20xx_radio_lora_set_modulation_params( const void* context,
const lr20xx_radio_lora_mod_params_t* mod_params );
/*
* Set LoRa packet params. In LR20XX_RADIO_LORA_PKT_EXPLICIT mode: pld_len_in_bytes=0 accepts all lengths;
* pld_len_in_bytes>0 accepts [1:pld_len_in_bytes], rejecting 0 or >pld_len_in_bytes with LORA_HEADER_ERROR IRQ.
/**
* @brief Set the packet parameters for LoRa packets
*
* The meaning of field pkt_params->pld_len_in_bytes depends on the packet mode selected:
* - If LR20XX_RADIO_LORA_PKT_EXPLICIT:
* - pld_len_in_bytes = 0 means that packets of all payload length will be accepted
* - pld_len_in_bytes > 0 means that packet with payload length in range [1:pld_len_in_bytes] will be accepted.
* Packet of payload length equals to 0 or strictly superior to pld_len_in_bytes will be rejected with IRQ
* LR20XX_SYSTEM_IRQ_LORA_HEADER_ERROR
*
* @param[in] context Chip implementation context
* @param[in] pkt_params Structure of LoRa packet configuration
*
* @return lr20xx_status_t Operation status
*/
lr20xx_status_t lr20xx_radio_lora_set_packet_params( const void* context,
const lr20xx_radio_lora_pkt_params_t* pkt_params );
/*
* Configure preamble-absent Rx timeout in LoRa symbols. n_symbols=0 disables.
* n_symbols>255 delegates to configure_timeout_by_mantissa_exponent_symbols via lr20xx_radio_convert_nb_symb_to_mant_exp.
/**
* @brief Configure a timeout given in number of LoRa symbols before stopping reception if no LoRa preamble symbols are
* detected
*
* A timeout interrupt is triggered if no LoRa preamble symbol is detected during the given period.
*
* Setting @p n_symbols to 0 disables the mechanism.
*
* If @p n_symbols is higher than 255, this function automatically propagate call to @ref
* lr20xx_radio_lora_configure_timeout_by_mantissa_exponent_symbols function, using @ref
* lr20xx_radio_convert_nb_symb_to_mant_exp to compute mantissa, exponent components.
*
* @param[in] context Chip implementation context
* @param[in] n_symbols The number of symbols to search for.
*
* @return lr20xx_status_t Operation status
*
* @see lr20xx_radio_lora_configure_timeout_by_mantissa_exponent_symbols, lr20xx_radio_convert_nb_symb_to_mant_exp
*/
lr20xx_status_t lr20xx_radio_lora_configure_timeout_by_number_of_symbols( const void* context, uint16_t n_symbols );
/*
* Configure preamble-absent Rx timeout via mantissa/exponent encoding: N = mant × 2^(2×exp+1).
* mantissa in [0:31], exponent in [0:7]. N=0 disables.
/**
* @brief Configure a timeout given in number of LoRa symbols before stopping reception if no LoRa preamble symbols are
* detected
*
* A timeout interrupt is triggered if no LoRa preamble symbol is detected during the given period.
*
* The number of symbol is computed as \f$ N_{symbols} = mantissa ^ {2 \times exponent + 1} \f$
*
* Setting @p mantissa and @p exponent to get a number of symbol equal to 0 disables the mechanism.
*
* @param[in] context Chip implementation context
* @param[in] mantissa Mantissa - from 0 to 31 - to compute the number of symbols
* @param[in] exponent Exponent - from 0 to 7 - to compute the number of symbols
*
* @return lr20xx_status_t
*
* @see lr20xx_radio_lora_configure_timeout_by_number_of_symbols, lr20xx_radio_convert_nb_symb_to_mant_exp
*/
lr20xx_status_t lr20xx_radio_lora_configure_timeout_by_mantissa_exponent_symbols( const void* context, uint8_t mantissa,
uint8_t exponent );
/*
* Compute mantissa/exponent [mant, exp] encoding for nb_symbol, finding the smallest N >= nb_symbol
* where N = mant × 2^(2×exp+1). Returns the actual N value used.
/**
* @brief Helper function to get the mantissa and exponent for a given number of symbol
*
* @remark This function computes the [mantissa, exponent] duple which corresponds to \f$ nb\_of\_symb \f$ : the
* smallest value verifying both following conditions:
* - \f$ nb\_of\_symb >= nb\_symbol \f$; and
* - \f$ nb\_of\_symb = mant * 2 ^ { 2 * exp + 1 } \f$
*
* @param [in] nb_symbol Number of symbols
* @param [out] mant Mantissa computed from @p nb_symbol
* @param [out] exp Exponent computed from @p nb_symbol
*
* @returns Number of symbols corresponding to the [mantissa, exponent] duple computed with the following formula:
* \f$ nb\_of\_symb = mant * 2 ^ { 2 * exp + 1 } \f$
*
* @see lr20xx_radio_lora_configure_timeout_by_mantissa_exponent_symbols,
* lr20xx_radio_lora_configure_timeout_by_number_of_symbols
*/
uint16_t lr20xx_radio_convert_nb_symb_to_mant_exp( const uint16_t nb_symbol, uint8_t* mant, uint8_t* exp );
/*
* Set LoRa syncword. Default 0x12 (LoRaWAN private). 0x34 = LoRaWAN public.
* Syncword is two 4-bit nibbles: syncword = ((block1 & 0x0F) << 4) | (block2 & 0x0F).
* block1 must not be 0. With SX1276 compatibility disabled, blocks are 4-bit signed [-8:7];
* with compatibility enabled they are 4-bit unsigned [0:15] matching SX127x.
* Different syncwords reduce but do not guarantee rejection of foreign packets.
/**
* @brief Configure the LoRa syncword.
*
* Default value is 0x12.
* Example of typical values:
* - LoRaWAN public network: 0x34
* - LoRaWAN private network: 0x12
*
* The syncword here should be understood as the concatenation of two 4 bits blocks as follows:
* @code{.c}
* uint8_t sync_block_1 = BLOCK_1;
* uint8_t sync_block_2 = BLOCK_2;
* uint8_t syncword = ((sync_block_1 & 0x0F) << 4) | (sync_block_2 & 0x0F);
* @endcode
*
* Here are some recommendations for syncword selection:
* - @p sync_block_1 must not be 0. So that syncword 0x0x must not be used;
* - avoid reusing a block value from another network
*
* Note that using different syncwords does not guarantee packet rejection. Receiver is just less likely to accept frame
* of different syncword.
*
* The following table indicates the compatible block values with other chips. Note that the block values are to be
* compared as signed integer when evaluating compatibility.
* A line indicates a set of values that are compatible together depending on other chips.
* Column <tt>SX126x/LR11xx/LR20xx syncword</tt> indicates block values used
* with @ref lr20xx_radio_lora_set_syncword function and SX1276 LoRa compatibility disabled (@ref
* lr20xx_workarounds_lora_disable_sx1276_compatibility_mode); the column <tt>LR20xx syncword SX127x compatibility</tt>
* indicates block values used with @ref lr20xx_radio_lora_set_syncword and with SX1276 LoRa compatibility enabled
* (@ref lr20xx_workarounds_lora_enable_sx1276_compatibility_mode).
*
* | SX126x/LR11xx/LR20xx syncword | LR20xx syncword SX127x compatibility | SX127x |
* | ----------------------------- | ------------------------------------ | --------------- |
* | 4 bits signed | 4 bits unsigned | 4 bits unsigned |
* | -8 | | |
* | -7 | | |
* | -6 | | |
* | -5 | | |
* | -4 | | |
* | -3 | | |
* | -2 | | |
* | -1 | | |
* | 0 | 0 | 0 |
* | 1 | 1 | 1 |
* | 2 | 2 | 2 |
* | 3 | 3 | 3 |
* | 4 | 4 | 4 |
* | 5 | 5 | 5 |
* | 6 | 6 | 6 |
* | 7 | 7 | 7 |
* | | 8 | 8 |
* | | 9 | 9 |
* | | 10 | 10 |
* | | 11 | 11 |
* | | 12 | 12 |
* | | 13 | 13 |
* | | 14 | 14 |
* | | 15 | 15 |
*
* @param[in] context Chip implementation context
* @param[in] syncword The syncword to configure
*
* @return lr20xx_status_t Operation status
*
* @see LR20XX_RADIO_LORA_SYNCWORD_LORAWAN_PUBLIC_NETWORK,
* LR20XX_RADIO_LORA_SYNCWORD_LORAWAN_PRIVATE_NETWORK
*/
lr20xx_status_t lr20xx_radio_lora_set_syncword( const void* context, uint8_t syncword );
/**
* @brief Configure the Channel Activity Detection (CAD) operation
*
* @param[in] context Chip implementation context
* @param[in] cad_params Structure of CAD parameter configuration
*
* @return lr20xx_status_t Operation status
*
* @see lr20xx_radio_lora_set_cad
*/
lr20xx_status_t lr20xx_radio_lora_configure_cad_params( const void* context,
const lr20xx_radio_lora_cad_params_t* cad_params );
/*
* Start CAD. Raises CAD_DONE IRQ; also raises CAD_DETECTED if signal found. Depending on cad_params exit_mode,
* chip either returns to fallback or starts the configured exit operation (RX or TX), whose IRQ fires after CAD IRQ.
/**
* @brief Start Channel Activity Detection (CAD) operation
*
* The CAD operation is a special mode of operation where the chip is looking for the presence of LoRa preamble symbols
* or for any Lora signal, depending on the setting in the @ref lr20xx_radio_lora_configure_cad_params command.
*
* At the end of the CAD operation a LR20XX_SYSTEM_IRQ_CAD_DONE is generated. If the CAD operation detects a signal, it
* also generates a LR20XX_SYSTEM_IRQ_CAD_DETECTED.
*
* Depending on the CAD configuration, the chip may either go back to the configured fallback mode, or enter the
* configured exit mode.
*
* If the exit mode is a radio operation the corresponding IRQ the CAD related IRQ(s) comes at the end CAD operation,
* and radio operations IRQ(s) of exit modes comes at the end of this radio operation.
*
* @param[in] context Chip implementation context
*
* @return lr20xx_status_t Operation status
*
* @see lr20xx_radio_lora_configure_cad_params
*/
lr20xx_status_t lr20xx_radio_lora_set_cad( const void* context );
/* Get Rx statistics. Reset on POR, retentionless sleep, or lr20xx_radio_common_reset_rx_stats */
/**
* @brief Get the internal statistics of received packets
*
* The internal statistics are reset on:
* - Power On Reset (POR)
* - sleep without memory retention
* - call to lr20xx_radio_common_reset_rx_stats
*
* @param[in] context Chip implementation context
* @param[out] statistics Pointer to a structure of statistic to populate with internal statistics
*
* @return lr20xx_status_t Operation status
*
* @see lr20xx_radio_common_reset_rx_stats
*/
lr20xx_status_t lr20xx_radio_lora_get_rx_statistics( const void* context,
lr20xx_radio_lora_rx_statistics_t* statistics );
/*
* Get last received LoRa packet status. Valid after RX_DONE or CAD_DONE, until next set_packet_params call.
* CRC/CR: from received header in EXPLICIT mode; from receiver config in IMPLICIT mode.
/**
* @brief Get the status of the last received LoRa packet
*
* Status is valid only after the end of a packet reception or CAD done and until the next LoRa packet configuration.
*
* CRC and coding rate source depends on the packet mode configured on the receiver:
* - If LR20XX_RADIO_LORA_PKT_EXPLICIT: it is obtained from the received payload
* - If LR20XX_RADIO_LORA_PKT_IMPLICIT: it is obtained from the receiver configuration
*
* @param[in] context Chip implementation context
* @param[out] pkt_status Pointer to a structure of packet status to populate
*
* @return lr20xx_status_t Operation status
*/
lr20xx_status_t lr20xx_radio_lora_get_packet_status( const void* context,
lr20xx_radio_lora_packet_status_t* pkt_status );
/*
* Configure LoRa address filtering. address_offset: payload byte offset of address field (header not counted).
* address_length in [0:8]; 0 disables filtering.
/**
* @brief Set the address for filtering in reception
*
* @param[in] context Chip implementation context
* @param[in] address_offset Offset in byte of the address field in the payload (header not counted)
* @param[in] address_length Address length in byte - in [0:8], 0 disables LoRa address filtering
* @param[in] address Address
*
* @return lr20xx_status_t Operation status
*/
lr20xx_status_t lr20xx_radio_lora_set_address( const void* context, uint8_t address_offset, uint8_t address_length,
const uint8_t* address );
/*
* Configure LoRa intra-packet frequency hopping. For SX1276 compatibility, call
* lr20xx_workarounds_lora_freq_hop_enable_sx1276_compatibility_mode after this.
/**
* @brief Configure LoRa intra-packet frequency hopping
*
* If the intra-packet frequency hopping must be compatible with SX1276, then the workaround @ref
* lr20xx_workarounds_lora_freq_hop_enable_sx1276_compatibility_mode must be called after calling @ref
* lr20xx_radio_lora_set_freq_hop.
*
* @param[in] context Chip implementation context
* @param[in] cfg Frequency hopping configuration
*
* @return lr20xx_status_t Operation status
*
* @see lr20xx_workarounds_lora_freq_hop_enable_sx1276_compatibility_mode
*/
lr20xx_status_t lr20xx_radio_lora_set_freq_hop( const void* context, const lr20xx_radio_lora_hopping_cfg_t* cfg );
/* Configure up to 3 CAD side detectors (additional SF detectors for CAD). n_side_detector_cad_configurations in [0:3] */
/**
* @brief Configure the LoRa Channel Activity Detection (CAD) side detectors
*
* Up to three CAD side detectors can be configured.
*
* @param context Chip implementation context
* @param side_detector_cad_configurations Array of side detector CAD configurations
* @param n_side_detector_cad_configurations Number of CAD side detector configurations in @p
* side_detector_cad_configurations. It is up to the caller to ensure that @p side_detector_cad_configurations contains
* at least @p n_side_detector_cad_configurations elements
*
* @return lr20xx_status_t Operation status
*/
lr20xx_status_t lr20xx_radio_lora_configure_side_detector_cad(
const void* context, const lr20xx_radio_lora_side_detector_cad_configuration_t* side_detector_cad_configurations,
uint8_t n_side_detector_cad_configurations );
/*
* Configure up to 3 LoRa side detectors (multi-SF Rx on same BW). n_side_detector_cfgs=0 or set_modulation_params
* disables all. Constraints: Rx-SF < side-SF; CAD-SF > side-SF; BW>=500 limits to 2 (or 1 if main SF>=SF10);
* all SFs distinct; max SF spread = 4. Demodulated SF readable via get_packet_status after RX_DONE.
/**
* @brief Configure LoRa side detectors
*
* The side detectors allow to receive on multiple spreading factors, but on the same bandwidth as main detector. Up to
* three side detectors can be configured.
*
* To disable all side detectors, there are 2 options:
* - call this command with @p n_side_detector_cfgs set to 0.
* - call @ref lr20xx_radio_lora_set_modulation_params
*
* Once a packet is received, it is possible to know which SF has been demodulated thanks to @ref
* lr20xx_radio_lora_get_packet_status.
*
* Specificities related to the side detector configuration:
* - For normal Rx operations, the SF configured with @ref lr20xx_radio_lora_set_modulation_params must be lower than
* the SF of the side detectors
* - For CAD operations, the SF configured with @ref lr20xx_radio_lora_set_modulation_params must be higher than the
* SF of the side detectors
* - With BW set to @ref LR20XX_RADIO_LORA_BW_500 or higher, maximum 2 side detectors are allowed except if the SF
* configured with @ref lr20xx_radio_lora_set_modulation_params is @ref LR20XX_RADIO_LORA_SF10 or higher where only 1
* side detector is allowed
* - All SF must be different
* - Difference between the highest and the lowest SF must be less than or equal to 4
*
* @param[in] context Chip implementation context
* @param[in] side_detector_cfgs Array of side detector configuration to set. It is up to the caller to ensure
* there are at least @p n_side_detector_cfgs
* @param[in] n_side_detector_cfgs Number of side detector to configure. Un-configured side detectors are
* disabled. Value must be in range [0:3] included.
*
* @return lr20xx_status_t Operation status
*/
lr20xx_status_t lr20xx_radio_lora_configure_side_detectors(
const void* context, const lr20xx_radio_lora_side_detector_cfg_t* side_detector_cfgs,
uint8_t n_side_detector_cfgs );
/* Set syncwords for up to 3 side detectors. n_syncword in [0:3]; unconfigured syncwords use default */
/**
* @brief Configure the LoRa syncwords for side detectors
*
* @param[in] context Chip implementation context
* @param[in] syncword Array of side detector syncword to set. It is up to the caller to ensure there are at least @p
* n_syncword
* @param[in] n_syncword Number of side detector syncword configure. Un-configured syncword are set to a default value.
* Value must be in range [0:3] included.
*
* @return lr20xx_status_t Operation status
*/
lr20xx_status_t lr20xx_radio_lora_set_side_detector_syncwords( const void* context, const uint8_t* syncword,
uint8_t n_syncword );
/* Time-on-air numerator (divide by BW in Hz to get seconds) */
/**
* @brief Compute the numerator for LoRa time-on-air computation.
*
* @remark To get the actual time-on-air in seconds, this value has to be divided by the LoRa bandwidth in Hertz.
*
* @param [in] pkt_p Pointer to the structure holding the LoRa packet parameters
* @param [in] mod_p Pointer to the structure holding the LoRa modulation parameters
*
* @returns LoRa time-on-air numerator
*/
uint32_t lr20xx_radio_lora_get_time_on_air_numerator( const lr20xx_radio_lora_pkt_params_t* pkt_p,
const lr20xx_radio_lora_mod_params_t* mod_p );
/**
* @brief Get the actual value in Hertz of a given LoRa bandwidth
*
* @param [in] bw LoRa bandwidth parameter
*
* @returns Actual LoRa bandwidth in Hertz
*/
uint32_t lr20xx_radio_lora_get_bw_in_hz( lr20xx_radio_lora_bw_t bw );
/*!
* @brief Get the time on air in ms for LoRa transmission
*
* @param [in] pkt_p Pointer to a structure holding the LoRa packet parameters
* @param [in] mod_p Pointer to a structure holding the LoRa modulation parameters
*
* @returns Time-on-air value in ms for LoRa transmission
*/
uint32_t lr20xx_radio_lora_get_time_on_air_in_ms( const lr20xx_radio_lora_pkt_params_t* pkt_p,
const lr20xx_radio_lora_mod_params_t* mod_p );
/*
* Recommended ppm_offset for given SF/BW:
* NO_PPM: SF<11, or BW>=500, or BW=250+SF11
* PPM_1_4: SF11/12 at BW<=406 (SX128x compat), BW=250+SF12, or SF12 at other narrow BWs
* See lr20xx_radio_lora_set_modulation_params.
/**
* @brief Helper function to compute recommended ppm offset value from SF and BW
*
* This helper function provides recommended PPM offset configuration based on the following rules
* - @ref LR20XX_RADIO_LORA_NO_PPM for all spreading factors, except for @ref LR20XX_RADIO_LORA_SF11 and @ref
* LR20XX_RADIO_LORA_SF12
* - @ref LR20XX_RADIO_LORA_PPM_1_4 for bandwidths @ref LR20XX_RADIO_LORA_BW_812, @ref LR20XX_RADIO_LORA_BW_406 and
* @ref LR20XX_RADIO_LORA_BW_203 to ensure SX128x compatibility
* - @ref LR20XX_RADIO_LORA_NO_PPM for bandwidths @ref LR20XX_RADIO_LORA_BW_1000 and @ref LR20XX_RADIO_LORA_BW_500
* - @ref LR20XX_RADIO_LORA_NO_PPM for bandwidth @ref LR20XX_RADIO_LORA_BW_250 and spreading factor @ref
* LR20XX_RADIO_LORA_SF11
* - @ref LR20XX_RADIO_LORA_PPM_1_4 for bandwidth @ref LR20XX_RADIO_LORA_BW_250 and spreading factor @ref
* LR20XX_RADIO_LORA_SF12
* - @ref LR20XX_RADIO_LORA_PPM_1_4 otherwise
*
* | Bandwidths | @ref LR20XX_RADIO_LORA_SF12 | @ref LR20XX_RADIO_LORA_SF11 | other spreading factors |
* | -- | -- | -- | -- |
* | @ref LR20XX_RADIO_LORA_BW_1000 | @ref LR20XX_RADIO_LORA_NO_PPM |||
* | @ref LR20XX_RADIO_LORA_BW_500 | @ref LR20XX_RADIO_LORA_NO_PPM |||
* | @ref LR20XX_RADIO_LORA_BW_250 | @ref LR20XX_RADIO_LORA_PPM_1_4 | @ref LR20XX_RADIO_LORA_NO_PPM ||
* | @ref LR20XX_RADIO_LORA_BW_812 | @ref LR20XX_RADIO_LORA_PPM_1_4 || @ref LR20XX_RADIO_LORA_NO_PPM |
* | @ref LR20XX_RADIO_LORA_BW_406 | @ref LR20XX_RADIO_LORA_PPM_1_4 || @ref LR20XX_RADIO_LORA_NO_PPM |
* | @ref LR20XX_RADIO_LORA_BW_203 | @ref LR20XX_RADIO_LORA_PPM_1_4 || @ref LR20XX_RADIO_LORA_NO_PPM |
* | other bandwidths | @ref LR20XX_RADIO_LORA_PPM_1_4 || @ref LR20XX_RADIO_LORA_NO_PPM |
*
* @param sf Spreading factor
* @param bw Bandwidth
*
* @return The recommended PPM offset configuration for the given spreading factor and bandwidth
*
* @see lr20xx_radio_lora_set_modulation_params
*/
lr20xx_radio_lora_ppm_t lr20xx_radio_lora_get_recommended_ppm_offset( lr20xx_radio_lora_sf_t sf,
lr20xx_radio_lora_bw_t bw );
@@ -52,10 +52,14 @@ extern "C" {
* --- PUBLIC MACROS -----------------------------------------------------------
*/
/*! @brief LoRa syncword for LoRaWAN public networks */
/**
* @brief LoRa syncword value for LoRaWAN public networks
*/
#define LR20XX_RADIO_LORA_SYNCWORD_LORAWAN_PUBLIC_NETWORK ( 0x34 )
/*! @brief LoRa syncword for LoRaWAN private networks */
/**
* @brief LoRa syncword value for LoRaWAN private networks
*/
#define LR20XX_RADIO_LORA_SYNCWORD_LORAWAN_PRIVATE_NETWORK ( 0x12 )
/*
@@ -174,7 +178,6 @@ typedef enum
//!< mode. Otherwise it enters in fallback mode
LR20XX_RADIO_LORA_CAD_EXIT_MODE_TX = 0x10, //!< If the CAD operation does not detect an activity, the chip enters
//!< in TX mode. Otherwise it enters in fallback mode
//!< (0x10, not 0x02: register encoding gap in LR2021 datasheet)
} lr20xx_radio_lora_cad_exit_mode_t;
/**
@@ -264,6 +267,7 @@ typedef struct lr20xx_radio_lora_rx_statistics_s
uint16_t n_crc_errors; //!< Number of received packets with CRC error
uint16_t n_header_errors; //!< Number of received packets with header error (Rx configured in
//!< LR20XX_RADIO_LORA_PKT_EXPLICIT and header CRC check failed)
uint16_t n_header_valid; //!< Number of detected header valid
uint16_t n_false_synchronisation; //!< Number of false synchronisation (preamble detected but syncword not
//!< detected, probably preamble detected on noise)
} lr20xx_radio_lora_rx_statistics_t;
@@ -285,6 +289,7 @@ typedef struct lr20xx_radio_lora_packet_status_s
//!< Equivalent to rssi_pkt_in_dbm if snr_pkt_raw is positive, to rssi_pkt_in_dbm
//!< + (snr_pkt_raw/4) if snr_pkt_raw is negative
uint8_t rssi_signal_pkt_half_dbm_count; //!< Count of 0.5 dBm to subtract to rssi_signal_pkt_in_dbm value in dBm
int32_t freq_offset_hz; //!< Frequency offset of the last packet received in Hz
} lr20xx_radio_lora_packet_status_t;
/**
+132 -13
View File
@@ -68,44 +68,163 @@ extern "C" {
* --- PUBLIC FUNCTIONS PROTOTYPES ---------------------------------------------
*/
/*
* Set OOK modulation params.
* Applies lr20xx_workarounds_dcdc_configure automatically unless LR20XX_WORKAROUNDS_DISABLE_AUTOMATIC_DCDC_CONFIGURE.
/**
* @brief Set the modulation parameters for OOK packets
*
* @param[in] context Chip implementation context
* @param[in] params Structure of OOK modulation configuration
*
* @return lr20xx_status_t Operation status
*/
lr20xx_status_t lr20xx_radio_ook_set_modulation_params( const void* context,
const lr20xx_radio_ook_mod_params_t* params );
/* Set OOK packet params. Note: explicit header + CRC disabled causes incorrect reception. */
/**
* @brief Set the packet parameters for OOK packets
*
* The OOK packet configuration with header explicit and CRC disabled is known to generate incorrect packet reception.
*
* @param[in] context Chip implementation context
* @param[in] params Structure of the OOK packet parameter to configure
*
* @returns Operation status
*/
lr20xx_status_t lr20xx_radio_ook_set_packet_params( const void* context, const lr20xx_radio_ook_pkt_params_t* params );
/**
* @brief Set the CRC configuration for OOK packets
*
* @param[in] context Chip implementation context
* @param[in] crc_polynomial Polynomial to use for CRC LFSR
* @param[in] crc_seed LFSR initial value
*
* @returns Operation status
*/
lr20xx_status_t lr20xx_radio_ook_set_crc_params( const void* context, uint32_t crc_polynomial, uint32_t crc_seed );
/*
* Set OOK syncword. syncword is a 32-bit value stored MSB-first in 4 bytes; nb_bits LSBs are used.
* bit_order controls OTA transmission order (LSBF or MSBF).
* Example: syncword=0x0000AA67, nb_bits=12 bits 0xA67 (12 LSBs).
/**
* @brief Set the syncword for OOK packets
*
* The argument \p syncword is a 4-byte array. However, it should be understood as 32-bit variable, where Most
* Significant Bit is the MSB of syncword[0] and Least Significant Bit is LSB of syncword[3].
*
* For instance:
*
* @code{.c}
* syncword = 0x0000AA67
* nb_bits = 12
* @endcode
*
* Then, syncword in bits is:
*
* @verbatim
* 0...0 01010101 01100111
* ^ ^ ^
* MSB nb_bit'th LSB
* @endverbatim
*
* Then, the bit stream sent over the air will be
* - if \p bit_order == LR20XX_RADIO_OOK_SYNCWORD_LSBF:
* @verbatim
* 111001101010
* @endverbatim
* - if \p bit_order == LR20XX_RADIO_OOK_SYNCWORD_MSBF:
* @verbatim
* 010101100111
* @endverbatim
*
* @param[in] context Chip implementation context
* @param[in] syncword Array holding the syncword value. It is up to the caller that this array holds at least
* LR20XX_RADIO_OOK_SYNCWORD_LENGTH bytes, even if nb_bits is not 32
* @param[in] nb_bits The number of significant bits in syncword to use for syncword. The significant bits are taken as
* Least Significant Bits of \p syncword argument. Value in range of [0:32]
* @param[in] bit_order The order of transmission of the selected bits of syncword over-the-air
*
* @returns Operation status
*/
lr20xx_status_t lr20xx_radio_ook_set_syncword( const void* context,
const uint8_t syncword[LR20XX_RADIO_OOK_SYNCWORD_LENGTH],
uint8_t nb_bits, lr20xx_radio_ook_syncword_bit_order_t bit_order );
/**
* @brief Set the node and broadcast addresses for OOK packets
*
* @param[in] context Chip implementation context
* @param[in] node_address Node address
* @param[in] broadcast_address Broadcast address
*
* @returns Operation status
*/
lr20xx_status_t lr20xx_radio_ook_set_addresses( const void* context, uint8_t node_address, uint8_t broadcast_address );
/* Get OOK Rx statistics; reset on POR, retention-less sleep, or lr20xx_radio_common_reset_rx_stats */
/**
* @brief Get the internal statistics of received OOK packets
*
* The internal statistics are reset on:
* - Power On Reset (POR)
* - sleep without memory retention
* - call to lr20xx_radio_common_reset_rx_stats
*
* @param[in] context Chip implementation context
* @param[out] statistics Pointer to a structure of statistic to populate with internal statistics
*
* @return lr20xx_status_t Operation status
*
* @see lr20xx_radio_common_reset_rx_stats
*/
lr20xx_status_t lr20xx_radio_ook_get_rx_statistics( const void* context, lr20xx_radio_ook_rx_statistics_t* statistics );
/*
* Get status of last received OOK packet.
* rssi_on/syncword available from SYNC_WORD_HEADER_VALID IRQ.
* rssi_avg/addr_match available from RX_DONE IRQ.
/**
* @brief Get the status of the last received OOK packet
*
* Availability of the packet status fields depend on the IRQ as follows:
* - Available from LR20XX_SYSTEM_IRQ_SYNC_WORD_HEADER_VALID:
* - lr20xx_radio_ook_packet_status_t.rssi_on_in_dbm
* - lr20xx_radio_ook_packet_status_t.rssi_on_half_dbm_count
* - Available from LR20XX_SYSTEM_IRQ_RX_DONE:
* - lr20xx_radio_ook_packet_status_t.rssi_avg_in_dbm
* - lr20xx_radio_ook_packet_status_t.rssi_avg_half_dbm_count
* - lr20xx_radio_ook_packet_status_t.is_addr_match_broadcast
* - lr20xx_radio_ook_packet_status_t.is_addr_match_node
*
* @param[in] context Chip implementation context
* @param[out] pkt_status Pointer to a structure of packet status to populate
*
* @return lr20xx_status_t Operation status
*/
lr20xx_status_t lr20xx_radio_ook_get_packet_status( const void* context, lr20xx_radio_ook_packet_status_t* pkt_status );
/**
* @brief Configure the Rx detector OOK packet
*
* @param[in] context Chip implementation context
* @param[in] rx_detector Rx detector configuration
*
* @return lr20xx_status_t Operation status
*/
lr20xx_status_t lr20xx_radio_ook_set_rx_detector( const void* context,
const lr20xx_radio_ook_rx_detector_t* rx_detector );
/**
* @brief Set whitening parameters for OOK packet
*
* @param[in] context Chip implementation context
* @param[in] params Whitening parameters
*
* @return lr20xx_status_t Operation status
*/
lr20xx_status_t lr20xx_radio_ook_set_whitening_params( const void* context,
const lr20xx_radio_ook_whitening_params_t* params );
/**
* @brief Get the time on air in ms for OOK transmission
*
* @param [in] pkt_p Pointer to a structure holding the OOK packet parameters
* @param [in] mod_p Pointer to a structure holding the OOK modulation parameters
* @param [in] syncword_len_in_bit Syncword length in bit
*
* @returns Time-on-air value in ms for OOK transmission
*/
uint32_t lr20xx_radio_ook_get_time_on_air_in_ms( const lr20xx_radio_ook_pkt_params_t* pkt_p,
const lr20xx_radio_ook_mod_params_t* mod_p,
uint8_t syncword_len_in_bit );
@@ -53,7 +53,10 @@ extern "C" {
* --- PUBLIC MACROS -----------------------------------------------------------
*/
/*! @brief OOK syncword length in bytes */
/**
* @brief Length in bytes of the OOK syncword
*
*/
#define LR20XX_RADIO_OOK_SYNCWORD_LENGTH ( 4 )
/*
@@ -238,7 +241,7 @@ typedef struct
} lr20xx_radio_ook_rx_detector_t;
/**
* @brief Whitening configuration for OOK packet
* @brief Rx detector configuration for OOK packet
*/
typedef struct
{
+54 -8
View File
@@ -37,6 +37,7 @@
* --- DEPENDENCIES ------------------------------------------------------------
*/
#include <stdbool.h>
#include "lr20xx_regmem.h"
#include "lr20xx_hal.h"
@@ -54,7 +55,6 @@
#define LR20XX_REGMEM_WRITE_REGMEM32_MASK_CMD_LENGTH ( 2 + 3 + 4 + 4 )
#define LR20XX_REGMEM_READ_REGMEM32_CMD_LENGTH ( 2 + 3 + 1 )
/* 32 words × 4 bytes = 128 bytes max payload; 256 provides headroom */
#define LR20XX_REGMEM_BUFFER_SIZE_MAX ( 256 )
/*
@@ -82,25 +82,66 @@ enum
* --- PRIVATE FUNCTIONS DECLARATION -------------------------------------------
*/
/* @warning caller must ensure cbuffer is sized for opcode + 3-byte address */
/*!
* @brief Helper function that fill both cbuffer with opcode and memory address
*
* It is typically used in read/write regmem32 functions.
*
* @warning It is up to the caller to ensure cbuffer is big enough to contain opcode and address!
*/
static void lr20xx_regmem_fill_cbuffer_opcode_address( uint8_t* cbuffer, uint16_t opcode, uint32_t address );
/* @warning caller must ensure cbuffer is sized for opcode + 3-byte address + length byte */
/*!
* @brief Helper function that fill both cbuffer with opcode memory address, and data length to read
*
* It is typically used in read functions.
*
* @warning It is up to the caller to ensure cbuffer is big enough to contain opcode and address!
*/
static void lr20xx_regmem_fill_cbuffer_opcode_address_length( uint8_t* cbuffer, uint16_t opcode, uint32_t address,
uint8_t length );
/* @warning caller must ensure cdata is sized for data_length × 4 bytes */
/*!
* @brief Helper function that fill both cbuffer with data
*
* It is typically used in write write regmem32 functions.
*
* @warning It is up to the caller to ensure cdata is big enough to contain all data!
*/
static void lr20xx_regmem_fill_cdata( uint8_t* cdata, const uint32_t* data, uint8_t data_length );
/* @warning caller must ensure cbuffer and cdata are appropriately sized */
/*!
* @brief Helper function that fill both cbuffer and cdata buffers with opcode, memory address and data
*
* It is typically used to factorize and write regmem32 operations. Behind the scene it calls the other helpers
* lr20xx_regmem_fill_cbuffer_opcode_address and lr20xx_regmem_fill_cdata.
*
* @warning It is up to the caller to ensure cbuffer and cdata are big enough to contain their respective information!
*/
static void lr20xx_regmem_fill_cbuffer_cdata_opcode_address_data( uint8_t* cbuffer, uint8_t* cdata, uint16_t opcode,
uint32_t address, const uint32_t* data,
uint8_t data_length );
/* @warning caller must ensure raw_buffer is at least out_buffer_length × 4 bytes */
/*!
* @brief Helper function that convert an array of uint8_t into an array of uint32_t
*
* Typically used in the read function returning uint32_t array.
*
* @warning It is up to the caller to ensure the raw_buffer is of length at least "out_buffer_length *
* sizeof(uint32_t)"!
*/
static void lr20xx_regmem_fill_out_buffer_from_raw_buffer( uint32_t* out_buffer, const uint8_t* raw_buffer,
uint8_t out_buffer_length );
/**
* @brief Check buffer length is appropriate for read/write regmem32 operations
*
* @param buffer_length The buffer length
* @return true The buffer length is correct for the operation
* @return false The buffer length is incorrect and the operation should not be executed
*/
static inline bool lr20xx_regmem_buffer_length_is_correct( uint8_t buffer_length );
/*
* -----------------------------------------------------------------------------
* --- PUBLIC FUNCTIONS DEFINITION ---------------------------------------------
@@ -112,7 +153,7 @@ lr20xx_status_t lr20xx_regmem_write_regmem32( const void* context, const uint32_
uint8_t cbuffer[LR20XX_REGMEM_WRITE_REGMEM32_CMD_LENGTH];
uint8_t cdata[LR20XX_REGMEM_BUFFER_SIZE_MAX];
if( length > LR20XX_REGMEM_MAX_WRITE_READ_WORDS )
if( !lr20xx_regmem_buffer_length_is_correct( length ) )
{
return LR20XX_STATUS_ERROR;
}
@@ -149,7 +190,7 @@ lr20xx_status_t lr20xx_regmem_read_regmem32( const void* context, const uint32_t
{
uint8_t cbuffer[LR20XX_REGMEM_READ_REGMEM32_CMD_LENGTH];
if( length > LR20XX_REGMEM_MAX_WRITE_READ_WORDS )
if( !lr20xx_regmem_buffer_length_is_correct( length ) )
{
return LR20XX_STATUS_ERROR;
}
@@ -223,4 +264,9 @@ void lr20xx_regmem_fill_out_buffer_from_raw_buffer( uint32_t* out_buffer, const
}
}
bool lr20xx_regmem_buffer_length_is_correct( uint8_t buffer_length )
{
return buffer_length <= LR20XX_REGMEM_MAX_WRITE_READ_WORDS;
}
/* --- EOF ------------------------------------------------------------------ */
@@ -52,7 +52,9 @@ extern "C" {
* --- PUBLIC MACROS -----------------------------------------------------------
*/
/*! @brief Max words per regmem32 read/write (LR2021 datasheet §5.4.3) */
/*!
* @brief Maximum number of words that can be written to / read from a LR20XX chip with regmem32 commands
*/
#define LR20XX_REGMEM_MAX_WRITE_READ_WORDS 32
/*
@@ -79,7 +81,7 @@ extern "C" {
* @param [in] context Chip implementation context
* @param [in] address The register memory address to start writing operation (only the 3 bytes LSB are relevant)
* @param [in] buffer The buffer of words to write into memory. Its size must be enough to contain length words.
* @param [in] length Number of words to write into memory
* @param [in] length Number of words to write into memory. Must be inferior or equal to 32.
*
* @returns Operation status
*
@@ -109,7 +111,7 @@ lr20xx_status_t lr20xx_regmem_write_regmem32_mask( const void* context, const ui
*
* @param [in] context Chip implementation context
* @param [in] address The register memory address to start reading operation (only the 3 bytes LSB are relevant)
* @param [in] length Number of words to read from memory
* @param [in] length Number of words to read from memory. Must be inferior or equal to 32.
* @param [out] buffer Pointer to a words array to be filled with content from memory. Its size must be enough to
* contain at least length words.
*
@@ -75,7 +75,7 @@
typedef enum lr20xx_status_e
{
LR20XX_STATUS_OK = 0,
LR20XX_STATUS_ERROR = 3, /* Must match lr20xx_hal_status_t ERROR value */
LR20XX_STATUS_ERROR = 3,
} lr20xx_status_t;
/*
+52 -12
View File
@@ -78,12 +78,35 @@
#define LR20XX_SYSTEM_SET_TEMP_COMP_CFG_CMD_LENGTH ( 2 + 1 )
#define LR20XX_SYSTEM_SET_NTC_PARAMS_CMD_LENGTH ( 2 + 5 )
#define LR20XX_SYSTEM_GET_STATUS_DIRECT_READ_LENGTH ( 6 ) /* stat1 + stat2 + 4-byte IRQ mask */
#define LR20XX_SYSTEM_VERSION_LENGTH ( 2 ) /* major + minor */
#define LR20XX_SYSTEM_ERRORS_LENGTH ( 2 ) /* 16-bit error bitmask */
#define LR20XX_SYSTEM_RANDOM_NUMBER_LENGTH ( 4 ) /* 32-bit random number */
#define LR20XX_SYSTEM_MEASURE_LENGTH ( 2 ) /* vbat / temp measurement */
#define LR20XX_SYSTEM_INTERRUPTS_LENGTH ( 4 ) /* 32-bit IRQ mask */
/*!
* @brief Length in byte of the status returned by the transceiver
*/
#define LR20XX_SYSTEM_GET_STATUS_DIRECT_READ_LENGTH ( 6 )
/*!
* @brief Length in byte of the version returned by the transceiver
*/
#define LR20XX_SYSTEM_VERSION_LENGTH ( 2 )
/*!
* @brief Length in byte of the error list returned by the transceiver
*/
#define LR20XX_SYSTEM_ERRORS_LENGTH ( 2 )
/*!
* @brief Length in byte of the random number returned by the transceiver
*/
#define LR20XX_SYSTEM_RANDOM_NUMBER_LENGTH ( 4 )
/*!
* @brief Length in byte of the measure (temperature or voltage) returned by the transceiver
*/
#define LR20XX_SYSTEM_MEASURE_LENGTH ( 2 )
/*!
* @brief Length in byte of the interrupt flags returned by the transceiver
*/
#define LR20XX_SYSTEM_INTERRUPTS_LENGTH ( 4 )
static const lr20xx_system_dio_t dio_list[] = {
LR20XX_SYSTEM_DIO_5, LR20XX_SYSTEM_DIO_6, LR20XX_SYSTEM_DIO_7, LR20XX_SYSTEM_DIO_8,
@@ -95,7 +118,9 @@ static const lr20xx_system_dio_t dio_list[] = {
* --- PRIVATE TYPES -----------------------------------------------------------
*/
/* System command opcodes */
/*!
* @brief Operating codes for system related operations
*/
enum
{
LR20XX_SYSTEM_GET_STATUS_OC = 0x0100,
@@ -135,9 +160,24 @@ enum
* --- PRIVATE FUNCTIONS DECLARATION -------------------------------------------
*/
/* Parse stat1 byte into stat1 struct; no-op if stat1 is NULL */
/*!
* @brief Fill stat1 structure with data from stat1_byte
*
* @remark If \p stat1 is NULL, the function does not perform any operation
*
* @param [in] stat1_byte stat1 byte
* @param [out] stat1 stat1 structure
*/
static void lr20xx_system_convert_stat1_byte_to_enum( uint8_t stat1_byte, lr20xx_system_stat1_t* stat1 );
/* Parse stat2 byte into stat2 struct; no-op if stat2 is NULL */
/*!
* @brief Fill stat2 structure with data from stat2_byte
*
* @remark If \p stat2 is NULL, the function does not perform any operation
*
* @param [in] stat2_byte stat2 byte
* @param [out] stat2 stat2 structure
*/
static void lr20xx_system_convert_stat2_byte_to_enum( uint8_t stat2_byte, lr20xx_system_stat2_t* stat2 );
/*
@@ -428,7 +468,7 @@ lr20xx_status_t lr20xx_system_get_temp( const void* context, lr20xx_system_value
if( status == LR20XX_STATUS_OK )
{
*temp = ( uint16_t ) ( ( ( ( uint16_t ) rbuffer[0] << 8 ) + ( uint16_t ) rbuffer[1] ) >> 3 ); /* 3 LSBs are status bits, not measurement data */
*temp = ( uint16_t ) ( ( ( ( uint16_t ) rbuffer[0] << 8 ) + ( uint16_t ) rbuffer[1] ) >> 3 );
}
return status;
@@ -464,8 +504,8 @@ lr20xx_status_t lr20xx_system_set_sleep_mode( const void* context, const lr20xx_
const uint8_t cbuffer[LR20XX_SYSTEM_SET_SLEEP_MODE_CMD_LENGTH] = {
( uint8_t ) ( LR20XX_SYSTEM_SET_SLEEP_MODE_OC >> 8 ),
( uint8_t ) ( LR20XX_SYSTEM_SET_SLEEP_MODE_OC >> 0 ),
( uint8_t ) ( ( ( sleep_cfg->is_ram_retention_enabled == true ) ? 0x02 : 0x00 ) + /* bit[1]: RAM retention */
( ( sleep_cfg->is_clk_32k_enabled == true ) ? 0x01 : 0x00 ) ), /* bit[0]: 32kHz clock */
( uint8_t ) ( ( ( sleep_cfg->is_ram_retention_enabled == true ) ? 0x02 : 0x00 ) +
( ( sleep_cfg->is_clk_32k_enabled == true ) ? 0x01 : 0x00 ) ),
( uint8_t ) ( sleep_time >> 24 ),
( uint8_t ) ( sleep_time >> 16 ),
( uint8_t ) ( sleep_time >> 8 ),
+382 -58
View File
@@ -68,147 +68,471 @@ extern "C" {
* --- PUBLIC FUNCTIONS PROTOTYPES ---------------------------------------------
*/
/*!
* @brief Reset the radio
*
* @param [in] context Chip implementation context.
*
* @returns Operation status
*/
lr20xx_status_t lr20xx_system_reset( const void* context );
/*!
* @brief Wake the radio up from sleep mode.
*
* @param [in] context Chip implementation context.
*
* @returns Operation status
*/
lr20xx_status_t lr20xx_system_wakeup( const void* context );
/*
* Return stat1, stat2, and irq_status. Any pointer may be NULL.
* Implemented as a bare SPI read (NOP bytes on MOSI); does NOT execute the GetStatus command.
* The LR20XX prefixes every SPI read response with stat1/stat2/irq_status automatically.
* Reset status in stat2 is NOT cleared by this call use lr20xx_system_clear_reset_status_info.
/*!
* @brief Return stat1, stat2, and irq_status
*
* @param [in] context Chip implementation context
* @param [out] stat1 Pointer to a variable for holding stat1. Can be NULL.
* @param [out] stat2 Pointer to a variable for holding stat2. Can be NULL.
* @param [out] irq_status Pointer to a variable for holding irq_status. Can be NULL.
*
* @returns Operation status
*
* @remark To simplify system integration, this function does not actually execute the GetStatus command, which would
* require bidirectional SPI communication. It obtains the stat1, stat2, and irq_status values by performing an ordinary
* SPI read (which is required to send null/NOP bytes on the MOSI line). This is possible since the LR20XX returns these
* values automatically whenever a read that does not directly follow a response-carrying command is performed.
* Unlike with the GetStatus command, however, the reset status information is NOT cleared by this command. The function
* @ref lr20xx_system_clear_reset_status_info may be used for this purpose when necessary.
*/
lr20xx_status_t lr20xx_system_get_status( const void* context, lr20xx_system_stat1_t* stat1,
lr20xx_system_stat2_t* stat2, lr20xx_system_irq_mask_t* irq_status );
/*!
* @brief Clear the reset status information stored in stat2
*
* @param [in] context Chip implementation context
*
* @returns Operation status
*/
lr20xx_status_t lr20xx_system_clear_reset_status_info( const void* context );
/*
* Read firmware version. Expected: LR2021 = major 0x01 / minor 0x18; LR2022 = major 0x02 / minor 0x00.
/*!
* @brief Return the version of the system
*
* The following table provides expected version per LR20xx derivatives:
*
* | Derivative | Version major | Version minor |
* | ---------- | ------------- | ------------- |
* | LR2021 | 0x01 | 0x18 |
* | LR2022 | 0x02 | 0x00 |
*
* @param [in] context Chip implementation context
* @param [out] version Pointer to the structure holding the system version
*
* @returns Operation status
*/
lr20xx_status_t lr20xx_system_get_version( const void* context, lr20xx_system_version_t* version );
/*
* Return system error flags. Remediation: calibration errors retry RC calibration;
* XOSC errors hardware issue, reset; PLL lock errors run PLL calibration or change frequency.
/*!
* @brief Return the system errors
*
* Errors may be fixed following:
* - calibration error can be fixed by attempting another RC calibration;
* - XOsc related errors may be due to hardware problems, can be fixed by reset;
* - PLL lock related errors can be due to not-locked PLL, or by attempting to use an out-of-band frequency, can be
* fixed by executing a PLL calibration, or by using other frequencies.
*
* @param [in] context Chip implementation context
* @param [out] errors Pointer to a value holding error flags
*
* @returns Operation status
*
* @see lr20xx_system_calibrate, lr20xx_radio_common_calibrate_front_end, lr20xx_system_clear_errors
*/
lr20xx_status_t lr20xx_system_get_errors( const void* context, lr20xx_system_errors_t* errors );
/*!
* @brief Clear all error flags pending.
*
* @param [in] context Chip implementation context
*
* @returns Operation status
*
* @see lr20xx_system_get_errors
*/
lr20xx_status_t lr20xx_system_clear_errors( const void* context );
/* Return number of available DIOs (valid range for lr20xx_system_dio_get_nth) */
/**
* @brief Returns the number of available DIOs
*
* @remark Also is the valid range for lr20xx_system_dio_get_nth.
*
* @return uint8_t the number of valid DIOs.
*
* @see lr20xx_system_dio_get_nth
*/
uint8_t lr20xx_system_dio_get_count( void );
/* Return nth DIO enum value; returns false if nth >= dio_count */
/**
* @brief Returns the nth value from the enum lr20xx_system_dio_t
*
* @param [in] nth from 0 to lr20xx_system_dio_get_count() - 1
* @param [out] dio Pointer to a value holding the corresponding DIO enum
* @return true if nth is a valid number, false otherwise
*
* @see lr20xx_system_dio_get_count, lr20xx_system_dio_t
*/
bool lr20xx_system_dio_get_nth( uint8_t nth, lr20xx_system_dio_t* dio );
/*
* Configure DIO function and drive mode. DIO state is re-evaluated on command.
* drive applied on sleep entry (if func != NONE); reset to NONE (or PULL_UP for DIO5/6) on wake without retention.
* TX/RX_TRIGGER uses the default timeout configured via set_default_rx_tx_timeout.
* LF_CLK_OUT only valid on DIO7DIO11.
* DIO5/DIO6 must be set to FUNC_NONE if connected to external components that could toggle them during cold-start.
/*!
* @brief Configure the function and the drive mode of a given DIO
*
* @remark @p drive is applied when entering sleep mode if @p func is not @ref LR20XX_SYSTEM_DIO_FUNC_NONE.
* When leaving sleep mode without retention, @p drive is reset to @ref LR20XX_SYSTEM_DIO_DRIVE_NONE (except for @p dio
* LR20XX_SYSTEM_DIO_5 and LR20XX_SYSTEM_DIO_6 where @p drive is reset to LR20XX_SYSTEM_DIO_DRIVE_PULL_UP).
*
* @remark The state of @p dio is reevaluated when sending this command
*
* @remark When @p func is set to either LR20XX_SYSTEM_DIO_FUNC_TX_TRIGGER or LR20XX_SYSTEM_DIO_FUNC_RX_TRIGGER, default
* timeout set through @ref lr20xx_radio_common_set_default_rx_tx_timeout or @ref
* lr20xx_radio_common_set_default_rx_tx_timeout_in_rtc_step is used when radio operation is triggered
*
* @remark On @ref LR20XX_SYSTEM_DIO_5, only @ref LR20XX_SYSTEM_DIO_DRIVE_PULL_UP for @p drive
*
* @remark Function @ref LR20XX_SYSTEM_DIO_FUNC_LF_CLK_OUT can only be used if @p dio is one of:
* - LR20XX_SYSTEM_DIO_7
* - LR20XX_SYSTEM_DIO_8
* - LR20XX_SYSTEM_DIO_9
* - LR20XX_SYSTEM_DIO_10
* - LR20XX_SYSTEM_DIO_11
*
* @ref LR20XX_SYSTEM_DIO_5 and @ref LR20XX_SYSTEM_DIO_6 must be configured explicitly to function @ref
* LR20XX_SYSTEM_DIO_FUNC_NONE if they are connected to an external component that could toggle their state between a
* cold start or a start without retention and the configuration of a function.
*
* @param [in] context Chip implementation context
* @param [in] dio DIO pin
* @param [in] func DIO pin function
* @param [in] drive DIO pin drive
*
* @returns Operation status
*/
lr20xx_status_t lr20xx_system_set_dio_function( const void* context, lr20xx_system_dio_t dio,
lr20xx_system_dio_func_t func, lr20xx_system_dio_drive_t drive );
/* Set RF switch configuration for a DIO; DIO state re-evaluated on command */
/*!
* @brief Set the RF switch configurations for a given DIO
*
* @remark The state of @p dio is reevaluated when sending this command
*
* @param [in] context Chip implementation context
* @param [in] dio DIO pin
* @param [in] rf_switch_cfg Pointer to a structure that holds the RF switch configuration for @p dio
*
* @returns Operation status
*/
lr20xx_status_t lr20xx_system_set_dio_rf_switch_cfg( const void* context, lr20xx_system_dio_t dio,
const lr20xx_system_dio_rf_switch_cfg_t rf_switch_cfg );
/*
* Map IRQs to a DIO. Each IRQ can only be mapped to one DIO at a time (last write wins).
* DIO state re-evaluated on command.
/*!
* @brief Set the interrupt configurations for a given DIO
*
* It is not possible to set the same IRQ on multiple DIOs. Only the last mapping for each IRQ is take into account.
*
* @remark The state of \p dio is reevaluated when sending this command
*
* @param [in] context Chip implementation context
* @param [in] dio DIO pin
* @param [in] irq_cfg Interrupt mask for \p dio
*
* @returns Operation status
*/
lr20xx_status_t lr20xx_system_set_dio_irq_cfg( const void* context, lr20xx_system_dio_t dio,
const lr20xx_system_irq_mask_t irq_cfg );
/*!
* @brief Clear requested bits in the internal pending interrupt register
*
* @param [in] context Chip implementation context
* @param [in] irqs_to_clear Variable that holds the interrupts to be cleared
*
* @returns Operation status
*
* @see lr20xx_system_get_and_clear_irq_status
*/
lr20xx_status_t lr20xx_system_clear_irq_status( const void* context, const lr20xx_system_irq_mask_t irqs_to_clear );
/* Atomically clear and return pending IRQ flags */
/**
* @brief This helper function clears any radio irq status flags that are set and returns the flags that were cleared.
*
* @param [in] context Chip implementation context.
* @param [out] irq Pointer to a variable for holding the system interrupt status.
*
* @returns Operation status
*
* @see lr20xx_system_clear_irq_status
*/
lr20xx_status_t lr20xx_system_get_and_clear_irq_status( const void* context, lr20xx_system_irq_mask_t* irq );
/*
* Select LF clock source. When switching to LR20XX_SYSTEM_LFCLK_EXT, the external clock must already be running
* and must remain running. Call lr20xx_system_calibrate after changing LF clock source.
/*!
* @brief Configure the source of the Low Frequency Clock (LF_CLK)
*
* When switching LF CLK to external source (@ref LR20XX_SYSTEM_LFCLK_EXT), the external clock source must be already
* running, and shall keep running afterwards.
*
* @param [in] context Chip implementation context
* @param [in] lfclock_cfg Low frequency clock configuration
*
* @returns Operation status
*
* @see lr20xx_system_calibrate, lr20xx_radio_common_calibrate_front_end, lr20xx_system_set_dio_function
*/
lr20xx_status_t lr20xx_system_cfg_lfclk( const void* context, const lr20xx_system_lfclk_cfg_t lfclock_cfg );
/*
* Set HF clock output scaling on the DIO configured with LR20XX_SYSTEM_DIO_FUNC_HF_CLK_OUT.
/*!
* @brief Configure the High Frequency clock scaling on the output
*
* This command sets the HF clock scaling on the DIO configured with functionality
* LR20XX_SYSTEM_DIO_FUNC_HF_CLK_OUT through lr20xx_system_set_dio_function
*
* @param [in] context Chip implementation context
* @param [in] hf_clk_scaling High frequency output scaling
*
* @returns Operation status
*
* @see lr20xx_system_set_dio_function
*/
lr20xx_status_t lr20xx_system_cfg_clk_output( const void* context, lr20xx_system_hf_clk_scaling_t hf_clk_scaling );
/*
* Configure TCXO supply voltage and start delay. start_delay_in_32mhz_step is a gating timeout in 32MHz ticks
* (1 tick = 31.25ns); max value 0xFFFFFFFF. Set to 0 to disable TCXO mode.
* If TCXO does not start within the delay, LR20XX_SYSTEM_ERRORS_HF_XOSC_START_MASK is set (check get_errors).
* If 32MHz RC is uncalibrated, actual start time may be up to 2x the configured delay.
/*!
* @brief Enable the usage of a TCXO as HF clock and configure supply voltage & start delay
*
* \p start_delay_in_32mhz_step is the time the firmware waits before going into RF mode, expressed in number of 32MHz
* clock ticks.
* The timeout duration is given by: \f$ start\_delay\_in\_ns = start\_delay\_in\_32mhz\_step \times 31.25 \f$
*
* The TCXO mode can be disabled by setting \p start_delay_in_32mhz_step to 0.
*
* In the situation where the TCXO has not started within \p start_delay_in_32mhz_step then the error bit
* LR20XX_SYSTEM_ERRORS_HF_XOSC_START_MASK will be set. It can be checked with a call to \p lr20xx_system_get_errors.
*
* It must be noted that the TCXO start time duration can last twice the duration of \p start_delay_in_32mhz_step
* lr20xx_system_calibrate if the internal 32MHz RC clock source is not calibrated. Refer to \p lr20xx_system_calibrate
* for details.
*
* The maximum value for \p start_delay_in_32mhz_step is 0xFFFFFFFF.
*
* @param [in] context Chip implementation context
* @param [in] supply_voltage Supply voltage value
* @param [in] start_delay_in_32mhz_step Gating time before which the radio starts its RF operation
*
* @returns Operation status
*
* @see lr20xx_system_calibrate, lr20xx_radio_common_calibrate_front_end, lr20xx_system_get_errors
*/
lr20xx_status_t lr20xx_system_set_tcxo_mode( const void* context,
const lr20xx_system_tcxo_supply_voltage_t supply_voltage,
const uint32_t start_delay_in_32mhz_step );
/* Set regulator mode; controls whether DCDC is enabled in STANDBY_XOSC, FS, RX, TX modes */
/*!
* @brief Configure the regulator mode to be used in specific modes
*
* \p reg_mode defines if the DC-DC converter is switched on in the following modes: STANDBY XOSC, FS, RX, TX.
*
* @param [in] context Chip implementation context
* @param [in] reg_mode Regulator mode configuration
*
* @returns Operation status
*/
lr20xx_status_t lr20xx_system_set_reg_mode( const void* context, const lr20xx_system_reg_mode_t reg_mode );
/*
* Calibrate selected blocks (bitmask of lr20xx_system_calibration_e). Can be called from any mode.
* Chip returns to STANDBY_RC on exit. Errors readable via lr20xx_system_get_errors.
* Run at boot; re-run AAF_MASK if temperature changes by >20°C; MU_MASK needs boot calibration only.
/*!
* @brief Calibrate the requested blocks
*
* This function can be called in any mode of the chip.
*
* The chip will return to standby RC mode on exit. Potential calibration issues can be read out with
* lr20xx_system_get_errors command.
*
* The calibration should be executed at boot. The calibration can then be executed again:
* - @ref lr20xx_system_calibration_e::LR20XX_SYSTEM_CALIB_AAF_MASK : should be calibrated again for a temperature
* change superior to 20 degree Celsius
* - @ref lr20xx_system_calibration_e::LR20XX_SYSTEM_CALIB_MU_MASK : initial calibration is enough
*
* @param [in] context Chip implementation context
* @param [in] blocks_to_calibrate Blocks to be calibrated - bitfield built with lr20xx_system_calibration_e
*
* @returns Operation status
*
* @see lr20xx_system_get_errors
*/
lr20xx_status_t lr20xx_system_calibrate( const void* context,
const lr20xx_system_calibration_mask_t blocks_to_calibrate );
/*
* Read supply voltage. RAW format: Vbat_V = (vbat/8192 × 5 - 1) × Vana (Vana typ. 1.35V; vbat is 13-bit).
* UNIT format: result in mV.
/*!
* @brief Get the value of the power supply voltage
*
* If @p format is set to LR20XX_SYSTEM_VALUE_FORMAT_RAW, Vbat value (in [V]) is a function of Vana (typ. 1.35V) and can
* be obtained using the following formula: \f$ Vbat_{V} = (\frac{vbat}{8192} \times 5 - 1) \times Vana \f$ where vbat
* is a 13-bit long value
*
* If @p format is set to LR20XX_SYSTEM_VALUE_FORMAT_UNIT, the power supply voltage is given in [mV]
*
* @param [in] context Chip implementation context
* @param [in] format Format of the returned value of @p vbat
* @param [in] res Resolution of the measure of @p vbat
* @param [out] vbat A pointer to the @p vbat value
*
* @returns Operation status
*/
lr20xx_status_t lr20xx_system_get_vbat( const void* context, lr20xx_system_value_format_t format,
lr20xx_system_meas_res_t res, uint16_t* vbat );
/*
* Read internal junction temperature. RAW format: Temp_°C = (temp[12:0]/8192 × Vana - Vbe25) × 1000/VbeSlope + 25
* (Vana typ. 1.35V, Vbe25 typ. 0.7295V, VbeSlope typ. -1.7mV/°C). UNIT format: °C in 13.5sb (integer + fractional).
* Configure TCXO with set_tcxo_mode before calling if TCXO is used.
/*!
* @brief Get the value of the internal junction temperature
*
* If @p format is set to LR20XX_SYSTEM_VALUE_FORMAT_RAW, the temperature (in [°C]) is a function of Vana (typ. 1.35V),
* Vbe25 (Vbe voltage @ 25°C, typ. 0.7295V) and VbeSlope (typ. -1.7mV/°C) using the following formula:
* \f$ Temperature_{°C} = (\frac{temp(12:0)}{8192} \times Vana - Vbe25) \times \frac{1000}{VbeSlope} + 25 \f$ where
* temp{12:0} is the value corresponding to the 12 LSBs of the output argument of @ref lr20xx_system_get_temp
*
* If @p format is set to LR20XX_SYSTEM_VALUE_FORMAT_UNIT, the temperature is given in [°C] in 13.5sb format, the first
* byte returned contains the integer part, the second the fractional part.
*
* @remark If a TCXO is used, make sure to configure it with @ref lr20xx_system_set_tcxo_mode before calling this
* function
*
* @param [in] context Chip implementation context
* @param [in] format Format of the returned value of @p temp
* @param [in] res Resolution of the measure
* @param [in] src Temperature source
* @param [out] temp A pointer to the @p temp value
*
* @returns Operation status
*/
lr20xx_status_t lr20xx_system_get_temp( const void* context, lr20xx_system_value_format_t format,
lr20xx_system_meas_res_t res, lr20xx_system_temp_src_t src, uint16_t* temp );
/*
* Read a 32-bit random number. Not suitable for cryptographic use. Radio must be in standby mode.
/*!
* @brief Read and return a 32-bit random number
*
* This random number generator is not suitable for cryptographic operations.
* It can be called during any mode without perturbation on ongoing Rx or Tx operation.
*
* @remark Radio operating mode must be set into standby.
*
* @param [in] context Chip implementation context
* @param [in] source Select source of entropy for random number generator
* @param [out] random_number 32-bit random number
*
* @returns Operation status
*/
lr20xx_status_t lr20xx_system_get_random_number( const void* context,
lr20xx_system_random_entropy_source_bitmask_t source,
uint32_t* random_number );
/* Enter sleep mode; sleep_time in LF clock steps (0 = sleep until wakeup pin) */
/*!
* @brief Switch the transceiver into sleep mode with the request configuration
*
* @param [in] context Chip implementation context
* @param [in] sleep_cfg Sleep configuration
* @param [in] sleep_time Sleep time in LF clock steps
*
* @returns Operation status
*/
lr20xx_status_t lr20xx_system_set_sleep_mode( const void* context, const lr20xx_system_sleep_cfg_t* sleep_cfg,
const uint32_t sleep_time );
/*!
* @brief Switch the transceiver into the requested stand-by mode
*
* @param [in] context Chip implementation context
* @param [in] standby_mode Requested stand-by mode
*
* @returns Operation status
*/
lr20xx_status_t lr20xx_system_set_standby_mode( const void* context, const lr20xx_system_standby_mode_t standby_mode );
/*!
* @brief Switch the transceiver into the Frequency Synthesis (FS) mode
*
* @param [in] context Chip implementation context
*
* @returns Operation status
*/
lr20xx_status_t lr20xx_system_set_fs_mode( const void* context );
/*
* Add a register to the sleep retention list. slot in [0:31]; address must be word-aligned (only 3 LSBs significant).
* Up to 32 additional registers beyond the hardware defaults can be retained across retentionless sleep.
/*!
* @brief Add a register to be saved in retention memory
*
* @remark This command is used when a register is not added by default to the retention memory. It gives the
* possibility to store up to 32 additional registers when entering sleep mode.
*
* @param [in] context Chip implementation context
* @param [in] slot Index in the storage list. Allowed values [0:31]
* @param [in] address Address of the register to be added to the list. Only the 3 LSBs are significant. Address must be
* word-aligned
*
* @returns Operation status
*
* @see lr20xx_system_set_sleep_mode
*/
lr20xx_status_t lr20xx_system_add_register_to_retention_mem( const void* context, uint8_t slot, uint32_t address );
/*!
* @brief Configure the low battery detector
*
* @param [in] context Chip implementation context
* @param [in] is_enabled Low battery detector activation
* @param [in] trim Trimming value defining the threshold used to trigger a low battery interrupt
*
* @returns Operation status
*/
lr20xx_status_t lr20xx_system_set_lbd_cfg( const void* context, bool is_enabled, lr20xx_system_lbd_trim_t trim );
/*
* Configure internal XTAL trim capacitors and post-ready wait time. XTA: 11.3pF + xta×0.47pF (max 47 steps = 33.39pF).
* XTB: 10.1pF + xtb×0.47pF (max 47 steps = 32.19pF). wait_time_us is an additional delay after XTAL readiness.
/*!
* @brief Configure the internal trimming capacitor values and XTAL start time
*
* @remark The device is fitted with internal programmable capacitors connected independently to the pins XTA and XTB of
* the device. Each capacitor can be controlled independently in steps of 0.47 pF added to the minimal value of 11.3pF
* for XTA and 10.1pF for XTB.
*
* The maximal capacitor value corresponds to 47 LSB steps added to the corresponding minimal value, so it is 33.39pF
* for XTA and 32.19pF for XTB.
*
* @param [in] context Chip implementation context
* @param [in] xta Value for the trimming capacitor connected to XTA pin
* @param [in] xtb Value for the trimming capacitor connected to XTB pin
* @param [in] wait_time_us Additional wait time after XTAL readiness in microsecond
*
* @returns Operation status
*/
lr20xx_status_t lr20xx_system_configure_xosc( const void* context, uint8_t xta, uint8_t xtb, uint8_t wait_time_us );
/*
* Configure TX heating compensation for XTAL 32MHz (not TCXO). Fails if TCXO is configured.
* Set is_ntc_en if an external NTC temperature sensor is present.
/*!
* @brief Set the temperature compensation configuration
*
* This command configures the heating compensation during Tx operations when XTAL 32MHz is used.
* This command will fail if a TCXO is configured.
*
* @param [in] context Chip implementation context
* @param [in] mode Temperature compensation mode
* @param [in] is_ntc_en Indicate if an external temperature sensor is available
*
* @returns Operation status
*/
lr20xx_status_t lr20xx_system_set_temp_comp_cfg( const void* context, lr20xx_system_temp_comp_mode_t mode,
bool is_ntc_en );
/* Set NTC parameters: ntc_r_ratio is 10.9b resistance bias ratio at 25°C; ntc_beta in units of 2K */
/*!
* @brief Set Negative Temperature Coefficient parameters
*
* @param [in] context Chip implementation context
* @param [in] ntc_r_ratio Resistance bias ratio (10.9b) - ratio between resistance bias and NTC resistance at 25°C
* @param [in] ntc_beta Beta coefficient (unit is 2 Kelvin)
* @param [in] delay First order time delay coefficient
*
* @returns Operation status
*/
lr20xx_status_t lr20xx_system_set_ntc_params( const void* context, uint16_t ntc_r_ratio, uint16_t ntc_beta,
uint8_t delay );
@@ -127,7 +127,7 @@ typedef struct lr20xx_system_version_s
} lr20xx_system_version_t;
/**
* @brief Sleep mode configuration
* @brief Version structure definition
*/
typedef struct lr20xx_system_sleep_cfg_s
{
@@ -345,8 +345,9 @@ typedef enum
*/
typedef enum lr20xx_system_reg_mode_e
{
LR20XX_SYSTEM_REG_MODE_LDO = 0x00, //!< (Default) Only use the Low-Dropout Regulator
LR20XX_SYSTEM_REG_MODE_DCDC = 0x02, //!< Switch on the DC-to-DC regulator in applicable chip modes
LR20XX_SYSTEM_REG_MODE_LDO = 0x00, //!< (Default) Only use the Low-Dropout Regulator
LR20XX_SYSTEM_REG_MODE_DCDC =
0x02, //!< Switch on the DC-to-DC regulator in applicable chip modes (a.k.a. SIMO converter)
} lr20xx_system_reg_mode_t;
/**
@@ -394,7 +395,12 @@ typedef enum lr20xx_system_temp_src_e
LR20XX_SYSTEM_TEMP_SRC_NTC = 0x02,
} lr20xx_system_temp_src_t;
/** @brief Entropy source selection for random number generator (default: PLL | ADC) */
/**
* @brief Select the entropy source to enable for random number generator
*
* It is advised to enable both PLL and ADC entropy sources.
* By default PLL and ADC are used as entropy sources.
*/
typedef enum
{
LR20XX_SYSTEM_RANDOM_ENTROPY_SOURCE_PLL = 0x01, //!< PLL is used as entropy source. The chip automatically goes to
@@ -403,7 +409,11 @@ typedef enum
//!< FS mode when needed, and goes back to original mode afterward.
} lr20xx_system_random_entropy_source_t;
/** @brief Bitmask of lr20xx_system_random_entropy_source_t values */
/**
* @brief Bit mask of entropy source to enable.
*
* The values are from @ref lr20xx_system_random_entropy_source_t.
*/
typedef uint8_t lr20xx_system_random_entropy_source_bitmask_t;
/**
@@ -45,56 +45,33 @@
#include "lr20xx_system.h"
#include "lr20xx_radio_ook.h"
#include "lr20xx_radio_common.h"
#include "lr20xx_radio_fifo.h"
/*
* -----------------------------------------------------------------------------
* --- PRIVATE MACROS-----------------------------------------------------------
*/
/* Semtech SWDR001 workaround register addresses and field masks */
#define LR20XX_WORKAROUND_BLUETOOTH_LE_PHY_CODED_SYNCWORDS ( 7 ) /* Semtech SWDR001 prescribed value */
#define LR20XX_WORKAROUND_BLUETOOTH_LE_2MBPS_PREAMBLE_LENGTH_BUFFER_LENGTH ( 7 ) /* Semtech SWDR001 prescribed value */
#define LR20XX_WORKAROUND_BLUETOOTH_LE_PHY_CODED_FREQUENCY_DRIFT_REGISTER_ADDRESS ( 0x00F30C28 ) /* Semtech SWDR001 */
#define LR20XX_WORKAROUND_BLUETOOTH_LE_PHY_CODED_FREQUENCY_DRIFT_REGISTER_MASK ( 0x1F << 5 )
#define LR20XX_WORKAROUND_BLUETOOTH_LE_PHY_CODED_FREQUENCY_DRIFT_VALUE ( 30 << 5 ) /* Semtech SWDR001 prescribed value; field occupies bits[9:5] */
#define LR20XX_WORKAROUND_LORA_SX1276_COMPATIBILITY_REGISTER_ADDRESS ( 0x00F30A14 ) /* Semtech SWDR001 */
#define LR20XX_WORKAROUND_LORA_SX1276_COMPATIBILITY_REGISTER_ADDRESS ( 0x00F30A14 )
#define LR20XX_WORKAROUND_LORA_SX1276_COMPATIBILITY_REGISTER_MASK ( 3 << 18 )
#define LR20XX_WORKAROUND_LORA_FREQ_HOP_SX1276_COMPATIBILITY_REGISTER_ADDRESS ( 0x00F30A24 ) /* Semtech SWDR001 */
#define LR20XX_WORKAROUND_LORA_FREQ_HOP_SX1276_COMPATIBILITY_REGISTER_ADDRESS ( 0x00F30A24 )
#define LR20XX_WORKAROUND_LORA_FREQ_HOP_SX1276_COMPATIBILITY_REGISTER_MASK ( 1 << 18 )
#define LR20XX_WORKAROUND_OOK_DETECTION_THRESHOLD_REGISTER_ADDRESS ( 0x00F30E14 ) /* Semtech SWDR001 */
#define LR20XX_WORKAROUND_OOK_DETECTION_THRESHOLD_REGISTER_ADDRESS ( 0x00F30E14 )
#define LR20XX_WORKAROUND_OOK_DETECTION_THRESHOLD_REGISTER_MASK ( 0x7F << 20 )
#define LR20XX_WORKAROUND_RTTOF_RF_FREQ_ADDRESS ( 0x00F40144 ) /* Semtech SWDR001 */
#define LR20XX_WORKAROUND_RTTOF_RF_FREQ_MASK ( 0x7F ) /* 7-bit PLL step fractional part */
#define LR20XX_WORKAROUND_RTTOF_RSSI_MAX_GAIN_REGISTER_ADDRESS ( 0x00F301A4 ) /* Semtech SWDR001 */
#define LR20XX_WORKAROUND_RTTOF_RSSI_POWER_OFFSET_REGISTER_ADDRESS ( 0x00F30128 ) /* Semtech SWDR001 */
#define LR20XX_WORKAROUND_DCDC_ADC_CTRL_REGISTER_ADDRESS ( 0x00F40200 ) /* Semtech SWDR001 */
#define LR20XX_WORKAROUND_DCDC_RX_PATH_REGISTER_ADDRESS ( 0x00F40430 ) /* Semtech SWDR001 */
#define LR20XX_WORKAROUND_DCDC_SWITCHER_REGISTER_ADDRESS ( 0x00F20024 ) /* Semtech SWDR001 */
#define LR20XX_WORKAROUND_DCDC_SWITCHER_RISE_REGISTER_MASK ( 0xF << 20 )
#define LR20XX_WORKAROUND_DCDC_SWITCHER_FALL_REGISTER_MASK ( 0xF << 16 )
#define LR20XX_WORKAROUND_DCDC_FREQ_LF_REGISTER_ADDRESS ( 0x80004C ) /* Semtech SWDR001 */
#define LR20XX_WORKAROUND_DCDC_RF_FREQ_ADDRESS ( LR20XX_WORKAROUND_RTTOF_RF_FREQ_ADDRESS )
#define LR20XX_WORKAROUND_RESULT_DEVIATION_CHANNEL_FILTER_ADDRESS ( 0xF3013C ) /* Semtech SWDR001 */
#define LR20XX_WORKAROUND_RESULT_DEVIATION_CHANNEL_FILTER_ADDRESS ( 0xF3013C )
#define LR20XX_WORKAROUND_RESULT_DEVIATION_CHANNEL_FILTER_MASK ( 0x38 )
#define LR20XX_WORKAROUND_RESULT_DEVIATION_CHANNEL_FILTER_VALUE ( 0x30 ) /* Semtech SWDR001 prescribed value; within mask 0x38 */
#define LR20XX_WORKAROUND_RESULT_DEVIATION_CHANNEL_FILTER_VALUE ( 0x30 )
#define LR20XX_WORKAROUND_RESULT_DEVIATION_DCC_ADDRESS ( 0xF30134 ) /* Semtech SWDR001 */
#define LR20XX_WORKAROUND_RESULT_DEVIATION_DCC_ADDRESS ( 0xF30134 )
#define LR20XX_WORKAROUND_RESULT_DEVIATION_DCC_MASK ( 0x1B )
#define LR20XX_WORKAROUND_RESULT_DEVIATION_DCC_MANAGER_VALUE ( 0x08 ) /* Semtech SWDR001 prescribed value; within mask 0x1B */
#define LR20XX_WORKAROUND_RESULT_DEVIATION_DCC_SUBORDINATE_VALUE ( 0x0A ) /* Semtech SWDR001 prescribed value; within mask 0x1B */
#define LR20XX_WORKAROUND_RESULT_DEVIATION_DCC_MANAGER_VALUE ( 0x08 )
#define LR20XX_WORKAROUND_RESULT_DEVIATION_DCC_SUBORDINATE_VALUE ( 0x0A )
#define LR20XX_WORKAROUND_RTTOF_EXTENDED_STUCK_ADDRESS ( 0x00F30B50 ) /* Semtech SWDR001 */
#define LR20XX_WORKAROUND_RTTOF_EXTENDED_STUCK_MASK ( 0x7 << 24 )
#define LR20XX_WORKAROUND_RTTOF_EXTENDED_STUCK_SET_VALUE ( 0x0 << 24 )
#define LR20XX_WORKAROUND_RTTOF_EXTENDED_STUCK_RESET_VALUE ( 0x1 << 24 )
#define LR20XX_WORKAROUND_CFG_IRQ_RX_FIFO_THRESHOLDS_REGISTER ( 0xF2A098 )
#define LR20XX_WORKAROUND_CFG_IRQ_TX_FIFO_THRESHOLDS_REGISTER ( 0xF2A09C )
/*
* -----------------------------------------------------------------------------
@@ -116,73 +93,42 @@
* --- PRIVATE FUNCTIONS DECLARATION -------------------------------------------
*/
/* Write SX1276 LoRa compatibility field; value=true enables */
/**
* @brief Helper function to write the appropriate field to store LoRa SX1276 compatibility parameter
*
* @param context Chip implementation context
* @param value True to enable the compatibility mode, false to disable it
* @return Operation status
*/
static lr20xx_status_t lr20xx_workaround_lora_sx1276_compatibility_write_value( const void* context, bool value );
/* Write SX1276 frequency-hopping compatibility field; value=true enables */
/**
* @brief Helper function to write the appropriate field to store LoRa frequency hopping SX1276 compatibility parameter
*
* @param context Chip implementation context
* @param value True to enable the compatibility mode, false to disable it
* @return Operation status
*/
static lr20xx_status_t lr20xx_workaround_lora_frequency_hopping_sx1276_compatibility_write_value( const void* context,
bool value );
/* Read SF bits from SX1276 compatibility register; used only when disabling the mode */
/**
* @brief Read the configured SF value configured
*
* This command is to be used only when disabling the SX1276 LoRa compatibility mode.
*
* @param context Chip implementation context
* @param [out] sf The configure SF
*
* @return Operation status
*/
static lr20xx_status_t lr20xx_workaround_lora_sx1276_compatibility_read_sf_value( const void* context, uint8_t* sf );
/* Read RTToF max gain (10-bit) and 6-bit signed power offset from hardware registers */
static lr20xx_status_t lr20xx_workarounds_rttof_rssi_computation_get_gain_power( const void* context,
uint16_t* max_gain,
int16_t* power_offset );
/* Apply RTToF RSSI correction formula (Semtech SWDR001) to a raw RSSI byte */
static uint8_t lr20xx_workarounds_rttof_rssi_computation_apply_correction( uint16_t max_gain, int16_t power_offset,
uint8_t raw_rssi );
/* Write DCDC LF switching frequency register (frequency in Hz) */
static lr20xx_status_t lr20xx_workaround_dcdc_set_frequency( const void* context, uint32_t frequency );
/* Read current RF frequency from PLL register; used only in DCDC workaround context */
static lr20xx_status_t lr20xx_workaround_dcdc_get_rf_frequency( const void* context, uint32_t* frequency );
/* Convert raw PLL step count to Hz: step_hz = 15625/2^14 ≈ 0.9537Hz */
static uint32_t pll_step_to_hz( uint32_t pll_steps );
/*
* -----------------------------------------------------------------------------
* --- PUBLIC FUNCTIONS DEFINITION ---------------------------------------------
*/
lr20xx_status_t lr20xx_workarounds_bluetooth_le_phy_coded_syncwords( const void* context )
{
const uint8_t cbuffer[LR20XX_WORKAROUND_BLUETOOTH_LE_PHY_CODED_SYNCWORDS] = { 0x02, 0x30, 0x01, 0x20,
0x00, 0x09, 0x00 };
return ( lr20xx_status_t ) lr20xx_hal_write( context, cbuffer, LR20XX_WORKAROUND_BLUETOOTH_LE_PHY_CODED_SYNCWORDS,
0, 0 );
}
lr20xx_status_t lr20xx_workarounds_bluetooth_le_phy_coded_frequency_drift( const void* context )
{
return lr20xx_regmem_write_regmem32_mask( context,
LR20XX_WORKAROUND_BLUETOOTH_LE_PHY_CODED_FREQUENCY_DRIFT_REGISTER_ADDRESS,
LR20XX_WORKAROUND_BLUETOOTH_LE_PHY_CODED_FREQUENCY_DRIFT_REGISTER_MASK,
LR20XX_WORKAROUND_BLUETOOTH_LE_PHY_CODED_FREQUENCY_DRIFT_VALUE );
}
lr20xx_status_t lr20xx_workarounds_bluetooth_le_phy_coded_frequency_drift_store_retention_mem( const void* context,
uint8_t slot )
{
return lr20xx_system_add_register_to_retention_mem(
context, slot, LR20XX_WORKAROUND_BLUETOOTH_LE_PHY_CODED_FREQUENCY_DRIFT_REGISTER_ADDRESS );
}
lr20xx_status_t lr20xx_workarounds_bluetooth_le_2mbps_preamble_length( const void* context )
{
const uint8_t cbuffer[LR20XX_WORKAROUND_BLUETOOTH_LE_2MBPS_PREAMBLE_LENGTH_BUFFER_LENGTH] = { 0x02, 0x30, 0x01,
0x21, 0x00, 0x07,
0x00 };
return ( lr20xx_status_t ) lr20xx_hal_write(
context, cbuffer, LR20XX_WORKAROUND_BLUETOOTH_LE_2MBPS_PREAMBLE_LENGTH_BUFFER_LENGTH, 0, 0 );
}
lr20xx_status_t lr20xx_workarounds_lora_enable_sx1276_compatibility_mode( const void* context )
{
return lr20xx_workaround_lora_sx1276_compatibility_write_value( context, true );
@@ -190,10 +136,11 @@ lr20xx_status_t lr20xx_workarounds_lora_enable_sx1276_compatibility_mode( const
lr20xx_status_t lr20xx_workarounds_lora_disable_sx1276_compatibility_mode( const void* context )
{
// 1. Get the currently configured SF value
uint8_t sf = 0;
const lr20xx_status_t get_sf_status = lr20xx_workaround_lora_sx1276_compatibility_read_sf_value( context, &sf );
/* SF6 requires compatibility mode even when "disabling" (SX1276 SF6 implicit-only constraint) */
// 2. Modify the compatibility mode value depending on currently configured SF
if( get_sf_status == LR20XX_STATUS_OK )
{
return lr20xx_workaround_lora_sx1276_compatibility_write_value( context, ( ( sf <= 6 ) ? true : false ) );
@@ -230,7 +177,6 @@ lr20xx_status_t lr20xx_workarounds_lora_freq_hop_sx1276_compatibility_mode_store
lr20xx_status_t lr20xx_workarounds_ook_set_detection_threshold_level( const void* context, int16_t threshold_level_db )
{
/* Register field is biased: +10 dB hardware offset + 64 to map signed dBm to unsigned field (Semtech SWDR001) */
const int threshold_db = threshold_level_db + 10 + 64;
return lr20xx_regmem_write_regmem32_mask(
context, LR20XX_WORKAROUND_OOK_DETECTION_THRESHOLD_REGISTER_ADDRESS,
@@ -426,92 +372,6 @@ int16_t lr20xx_workarounds_ook_get_default_detection_threshold_level( lr20xx_rad
}
}
lr20xx_status_t lr20xx_workarounds_rttof_truncate_pll_freq_step( const void* context )
{
return lr20xx_regmem_write_regmem32_mask( context, LR20XX_WORKAROUND_RTTOF_RF_FREQ_ADDRESS,
LR20XX_WORKAROUND_RTTOF_RF_FREQ_MASK, 0 );
}
lr20xx_status_t lr20xx_workarounds_rttof_rssi_computation( const void* context, uint8_t rssi1_raw_value,
uint8_t rssi2_raw_value, uint8_t* rssi1_raw_fixed,
uint8_t* rssi2_raw_fixed )
{
uint16_t max_gain = 0;
int16_t power_offset = 0;
RETURN_STATUS_ON_NOT_OK(
lr20xx_workarounds_rttof_rssi_computation_get_gain_power( context, &max_gain, &power_offset ) );
( *rssi1_raw_fixed ) =
lr20xx_workarounds_rttof_rssi_computation_apply_correction( max_gain, power_offset, rssi1_raw_value );
if( rssi2_raw_fixed != 0 )
{
( *rssi2_raw_fixed ) =
lr20xx_workarounds_rttof_rssi_computation_apply_correction( max_gain, power_offset, rssi2_raw_value );
}
return LR20XX_STATUS_OK;
}
lr20xx_status_t lr20xx_workarounds_dcdc_reset( const void* context )
{
/* Rise/fall timing fields (bits 23:20 and 19:16): default values 15,15 per Semtech SWDR001 */
RETURN_STATUS_ON_NOT_OK(
lr20xx_regmem_write_regmem32_mask( context, LR20XX_WORKAROUND_DCDC_SWITCHER_REGISTER_ADDRESS,
LR20XX_WORKAROUND_DCDC_SWITCHER_RISE_REGISTER_MASK, 15 << 20 ) );
RETURN_STATUS_ON_NOT_OK(
lr20xx_regmem_write_regmem32_mask( context, LR20XX_WORKAROUND_DCDC_SWITCHER_REGISTER_ADDRESS,
LR20XX_WORKAROUND_DCDC_SWITCHER_FALL_REGISTER_MASK, 15 << 16 ) );
return lr20xx_workaround_dcdc_set_frequency( context, 2800000 ); /* 2.8MHz default switching frequency */
}
lr20xx_status_t lr20xx_workarounds_dcdc_configure( const void* context )
{
uint32_t adc_ctrl_raw = 0;
RETURN_STATUS_ON_NOT_OK(
lr20xx_regmem_read_regmem32( context, LR20XX_WORKAROUND_DCDC_ADC_CTRL_REGISTER_ADDRESS, &adc_ctrl_raw, 1 ) );
const uint32_t ana_dec = ( adc_ctrl_raw >> 8 ) & 0x7;
uint32_t rx_path_raw = 0;
RETURN_STATUS_ON_NOT_OK(
lr20xx_regmem_read_regmem32( context, LR20XX_WORKAROUND_DCDC_RX_PATH_REGISTER_ADDRESS, &rx_path_raw, 1 ) );
const bool is_rx_hf = ( ( rx_path_raw & 0x3 ) == 1 );
/* Rise=11,Fall=13 for narrow-band LF RX path; Rise=15,Fall=15 otherwise — Semtech SWDR001 */
if( ( is_rx_hf == false ) && ( ( ana_dec == 1 ) || ( ana_dec == 2 ) ) )
{
RETURN_STATUS_ON_NOT_OK(
lr20xx_regmem_write_regmem32_mask( context, LR20XX_WORKAROUND_DCDC_SWITCHER_REGISTER_ADDRESS,
LR20XX_WORKAROUND_DCDC_SWITCHER_RISE_REGISTER_MASK, 11 << 20 ) );
RETURN_STATUS_ON_NOT_OK(
lr20xx_regmem_write_regmem32_mask( context, LR20XX_WORKAROUND_DCDC_SWITCHER_REGISTER_ADDRESS,
LR20XX_WORKAROUND_DCDC_SWITCHER_FALL_REGISTER_MASK, 13 << 16 ) );
}
else
{
RETURN_STATUS_ON_NOT_OK(
lr20xx_regmem_write_regmem32_mask( context, LR20XX_WORKAROUND_DCDC_SWITCHER_REGISTER_ADDRESS,
LR20XX_WORKAROUND_DCDC_SWITCHER_RISE_REGISTER_MASK, 15 << 20 ) );
RETURN_STATUS_ON_NOT_OK(
lr20xx_regmem_write_regmem32_mask( context, LR20XX_WORKAROUND_DCDC_SWITCHER_REGISTER_ADDRESS,
LR20XX_WORKAROUND_DCDC_SWITCHER_FALL_REGISTER_MASK, 15 << 16 ) );
}
/* ana_dec==1: 4.3MHz switching; otherwise: 2.8MHz — Semtech SWDR001 */
if( ana_dec == 1 )
{
return lr20xx_workaround_dcdc_set_frequency( context, 4300000 );
}
else
{
return lr20xx_workaround_dcdc_set_frequency( context, 2800000 );
}
}
lr20xx_status_t lr20xx_workarounds_dcdc_store_retention_mem( const void* context, uint8_t slot )
{
return lr20xx_system_add_register_to_retention_mem( context, slot,
LR20XX_WORKAROUND_DCDC_SWITCHER_REGISTER_ADDRESS );
}
lr20xx_status_t lr20xx_workarounds_rttof_results_deviation( const void* context, bool is_manager )
{
RETURN_STATUS_ON_NOT_OK(
@@ -533,24 +393,30 @@ lr20xx_status_t lr20xx_workarounds_rttof_results_deviation_store_retention_mem(
LR20XX_WORKAROUND_RESULT_DEVIATION_DCC_ADDRESS );
}
lr20xx_status_t lr20xx_workarounds_rttof_extended_stuck_second_request_enable( const void* context )
lr20xx_status_t lr20xx_workarounds_1024_byte_fifo_cfg_irq(
const void* context, lr20xx_radio_fifo_flag_t rx_fifo_irq_enable, lr20xx_radio_fifo_flag_t tx_fifo_irq_enable,
uint16_t rx_fifo_high_threshold, uint16_t tx_fifo_low_threshold, uint16_t rx_fifo_low_threshold,
uint16_t tx_fifo_high_threshold )
{
return lr20xx_regmem_write_regmem32_mask( context, LR20XX_WORKAROUND_RTTOF_EXTENDED_STUCK_ADDRESS,
LR20XX_WORKAROUND_RTTOF_EXTENDED_STUCK_MASK,
LR20XX_WORKAROUND_RTTOF_EXTENDED_STUCK_SET_VALUE );
RETURN_STATUS_ON_NOT_OK( lr20xx_radio_fifo_cfg_irq( context, rx_fifo_irq_enable, tx_fifo_irq_enable,
rx_fifo_high_threshold, 0, 0, tx_fifo_high_threshold ) );
const uint32_t rx_threshold_raw = ( uint32_t ) rx_fifo_low_threshold + ( rx_fifo_high_threshold << 16u );
const uint32_t tx_threshold_raw = ( uint32_t ) tx_fifo_low_threshold + ( tx_fifo_high_threshold << 16u );
RETURN_STATUS_ON_NOT_OK( lr20xx_regmem_write_regmem32(
context, LR20XX_WORKAROUND_CFG_IRQ_RX_FIFO_THRESHOLDS_REGISTER, &rx_threshold_raw, 1 ) );
return lr20xx_regmem_write_regmem32( context, LR20XX_WORKAROUND_CFG_IRQ_TX_FIFO_THRESHOLDS_REGISTER,
&tx_threshold_raw, 1 );
}
lr20xx_status_t lr20xx_workarounds_rttof_extended_stuck_second_request_disable( const void* context )
lr20xx_status_t lr20xx_workarounds_1024_byte_fifo_cfg_irq_store_retention_mem( const void* context,
uint8_t retention_slot_rx_thresholds,
uint8_t retention_slot_tx_thresholds )
{
return lr20xx_regmem_write_regmem32_mask( context, LR20XX_WORKAROUND_RTTOF_EXTENDED_STUCK_ADDRESS,
LR20XX_WORKAROUND_RTTOF_EXTENDED_STUCK_MASK,
LR20XX_WORKAROUND_RTTOF_EXTENDED_STUCK_RESET_VALUE );
}
lr20xx_status_t lr20xx_workarounds_rttof_extended_stuck_second_request_store_retention_mem( const void* context,
uint8_t slot )
{
return lr20xx_system_add_register_to_retention_mem( context, slot, LR20XX_WORKAROUND_RTTOF_EXTENDED_STUCK_ADDRESS );
RETURN_STATUS_ON_NOT_OK( lr20xx_system_add_register_to_retention_mem(
context, retention_slot_rx_thresholds, LR20XX_WORKAROUND_CFG_IRQ_RX_FIFO_THRESHOLDS_REGISTER ) );
return lr20xx_system_add_register_to_retention_mem( context, retention_slot_tx_thresholds,
LR20XX_WORKAROUND_CFG_IRQ_TX_FIFO_THRESHOLDS_REGISTER );
}
/*
@@ -580,61 +446,9 @@ lr20xx_status_t lr20xx_workaround_lora_sx1276_compatibility_read_sf_value( const
context, LR20XX_WORKAROUND_LORA_SX1276_COMPATIBILITY_REGISTER_ADDRESS, &raw_register_value, 1 );
if( read_status == LR20XX_STATUS_OK )
{
*sf = raw_register_value & 0x0f; /* SF is stored in bits [3:0] */
*sf = raw_register_value & 0x0f;
}
return read_status;
}
lr20xx_status_t lr20xx_workarounds_rttof_rssi_computation_get_gain_power( const void* context, uint16_t* max_gain,
int16_t* power_offset )
{
uint32_t max_gain_raw = 0;
RETURN_STATUS_ON_NOT_OK( lr20xx_regmem_read_regmem32(
context, LR20XX_WORKAROUND_RTTOF_RSSI_MAX_GAIN_REGISTER_ADDRESS, &max_gain_raw, 1 ) );
( *max_gain ) = ( uint16_t ) ( max_gain_raw & 0x03FF ); /* 10-bit gain field */
uint32_t power_offset_raw = 0;
RETURN_STATUS_ON_NOT_OK( lr20xx_regmem_read_regmem32(
context, LR20XX_WORKAROUND_RTTOF_RSSI_POWER_OFFSET_REGISTER_ADDRESS, &power_offset_raw, 1 ) );
/* 6-bit two's-complement field at bit[11:6]: sign-extend by subtracting 64 if > 31 */
const int16_t power_offset_raw_value = ( power_offset_raw >> 6 ) & 0x3F;
( *power_offset ) = ( int16_t ) ( ( ( power_offset_raw_value ) > 32 ) ? ( power_offset_raw_value - ( int16_t ) 64 )
: power_offset_raw_value );
return LR20XX_STATUS_OK;
}
uint8_t lr20xx_workarounds_rttof_rssi_computation_apply_correction( uint16_t max_gain, int16_t power_offset,
uint8_t raw_rssi )
{
/* 208 = RSSI register bias per Semtech SWDR001 RSSI correction formula */
return ( uint8_t ) ( 208 + ( max_gain >> 1 ) + power_offset - ( raw_rssi << 1 ) );
}
lr20xx_status_t lr20xx_workaround_dcdc_set_frequency( const void* context, uint32_t frequency )
{
/* 1.048576 = 2^20 / 1e6: converts Hz to LF register units (Semtech SWDR001) */
const uint32_t freq_lf = ( uint32_t ) ( ( float ) frequency * 1.048576f );
RETURN_STATUS_ON_NOT_OK(
lr20xx_regmem_write_regmem32( context, LR20XX_WORKAROUND_DCDC_FREQ_LF_REGISTER_ADDRESS, &freq_lf, 1 ) );
uint32_t rf_frequency = 0;
RETURN_STATUS_ON_NOT_OK( lr20xx_workaround_dcdc_get_rf_frequency( context, &rf_frequency ) );
return lr20xx_radio_common_set_rf_freq( context, rf_frequency );
}
lr20xx_status_t lr20xx_workaround_dcdc_get_rf_frequency( const void* context, uint32_t* frequency )
{
uint32_t raw_rf_freq = 0;
RETURN_STATUS_ON_NOT_OK(
lr20xx_regmem_read_regmem32( context, LR20XX_WORKAROUND_DCDC_RF_FREQ_ADDRESS, &raw_rf_freq, 1 ) );
*frequency = pll_step_to_hz( raw_rf_freq );
return LR20XX_STATUS_OK;
}
uint32_t pll_step_to_hz( uint32_t pll_steps )
{
const uint_least64_t numerator = ( ( uint_least64_t ) pll_steps * ( uint_least64_t ) 15625ULL );
const uint_least64_t denominator = ( ( uint_least64_t ) ( 1 << 14 ) ); /* PLL step = 15625/2^14 Hz */
return ( uint32_t ) ( ( numerator + denominator - 1 ) / denominator );
}
/* --- EOF ------------------------------------------------------------------ */
@@ -48,31 +48,13 @@ extern "C" {
#include <stdbool.h>
#include "lr20xx_status.h"
#include "lr20xx_radio_fsk_common_types.h"
#include "lr20xx_radio_fifo_types.h"
/*
* -----------------------------------------------------------------------------
* --- PUBLIC MACROS -----------------------------------------------------------
*/
#ifndef LR20XX_WORKAROUNDS_DISABLE_AUTOMATIC_DCDC_RESET
#define LR20XX_WORKAROUNDS_CONDITIONAL_APPLY_AUTOMATIC_DCDC_RESET( cont ) lr20xx_workarounds_dcdc_reset( cont )
#else
#define LR20XX_WORKAROUNDS_CONDITIONAL_APPLY_AUTOMATIC_DCDC_RESET( cont ) LR20XX_STATUS_OK
#endif // LR20XX_WORKAROUNDS_DISABLE_AUTOMATIC_DCDC_RESET
#ifndef LR20XX_WORKAROUNDS_DISABLE_AUTOMATIC_DCDC_CONFIGURE
#define LR20XX_WORKAROUNDS_CONDITIONAL_APPLY_AUTOMATIC_DCDC_CONFIGURE( cont ) lr20xx_workarounds_dcdc_configure( cont )
#else
#define LR20XX_WORKAROUNDS_CONDITIONAL_APPLY_AUTOMATIC_DCDC_CONFIGURE( cont ) LR20XX_STATUS_OK
#endif // LR20XX_WORKAROUNDS_DISABLE_AUTOMATIC_DCDC_CONFIGURE
#ifndef LR20XX_WORKAROUND_DISABLE_AUTOMATIC_BLE_2MBPS_PREAMBLE_LENGTH
#define LR20XX_WORKAROUND_CONDITIONAL_APPLY_BLE_2MBPS_PREAMBLE_LENGTH( cont ) \
lr20xx_workarounds_bluetooth_le_2mbps_preamble_length( cont )
#else
#define LR20XX_WORKAROUND_CONDITIONAL_APPLY_BLE_2MBPS_PREAMBLE_LENGTH( cont ) LR20XX_STATUS_OK
#endif // LR20XX_WORKAROUND_DISABLE_AUTOMATIC_BLE_2MBPS_PREAMBLE_LENGTH
/*
* -----------------------------------------------------------------------------
* --- PUBLIC CONSTANTS --------------------------------------------------------
@@ -88,110 +70,234 @@ extern "C" {
* --- PUBLIC FUNCTIONS PROTOTYPES ---------------------------------------------
*/
/* Call after lr20xx_radio_bluetooth_le_set_pkt_params when PHY is LE_CODED_125KB or LE_CODED_500KB */
lr20xx_status_t lr20xx_workarounds_bluetooth_le_phy_coded_syncwords( const void* context );
/* Call after lr20xx_radio_bluetooth_le_set_pkt_params when PHY is LE_CODED_125KB or LE_CODED_500KB */
lr20xx_status_t lr20xx_workarounds_bluetooth_le_phy_coded_frequency_drift( const void* context );
/* Persist BLE coded-PHY frequency drift register across sleep; slot in [0:31] */
lr20xx_status_t lr20xx_workarounds_bluetooth_le_phy_coded_frequency_drift_store_retention_mem( const void* context,
uint8_t slot );
/*
* Fix incorrect default preamble length for BLE 2Mbps mode.
* Call after lr20xx_radio_bluetooth_le_set_modulation_params when PHY is LE_2M.
* Applied automatically unless LR20XX_WORKAROUND_DISABLE_AUTOMATIC_BLE_2MBPS_PREAMBLE_LENGTH is defined.
*/
lr20xx_status_t lr20xx_workarounds_bluetooth_le_2mbps_preamble_length( const void* context );
/*
* Enable SX1276 LoRa compatibility: SF6 implicit mode and syncword nibbles > 7 for all SF.
* Call after lr20xx_radio_lora_set_modulation_params.
/**
* @brief Enable LoRa compatibility mode with SX1276
*
* If the SX1276 LoRa compatibility is required, this workaround must be called after calling @ref
* lr20xx_radio_lora_set_modulation_params.
*
* SX1276 LoRa compatibility mode allows:
* - transmission to, and reception from, SX1276 LoRa packets at SF6 only in implicit mode (@ref
* LR20XX_RADIO_LORA_PKT_IMPLICIT); and
* - syncword nibbles greater than 7 for all SF.
*
* @param context Chip implementation context
*
* @return Operation status
*
* @see lr20xx_workarounds_lora_disable_sx1276_compatibility_mode,
* lr20xx_workarounds_lora_sx1276_compatibility_mode_store_retention_mem
*/
lr20xx_status_t lr20xx_workarounds_lora_enable_sx1276_compatibility_mode( const void* context );
/* Disable SX1276 LoRa compatibility; may be called before or after lr20xx_radio_lora_set_modulation_params */
/**
* @brief Disable the LoRa compatibility mode with SX1276
*
* To disable the SX1276 LoRa compatibility mode, this workaround can be call either before or after @ref
* lr20xx_radio_lora_set_modulation_params.
*
* @param context Chip implementation context
*
* @return Operation status
*
* @see lr20xx_workarounds_lora_enable_sx1276_compatibility_mode,
* lr20xx_workarounds_lora_sx1276_compatibility_mode_store_retention_mem
*/
lr20xx_status_t lr20xx_workarounds_lora_disable_sx1276_compatibility_mode( const void* context );
/* Persist SX1276 LoRa compatibility register across sleep; slot in [0:31] */
/**
* @brief Store the LoRa SX1276 compatibility mode in retention memory
*
* Calling this function allows to store the SX1276 LoRa compatible state during sleep mode.
* This helper function internally calls @ref lr20xx_system_add_register_to_retention_mem with the appropriate register
* address.
*
* @param context Chip implementation context
* @param slot Index in the storage list. Allowed values [0:31]
*
* @return Operation status
*
* @see lr20xx_system_add_register_to_retention_mem, lr20xx_workarounds_lora_enable_sx1276_compatibility_mode,
* lr20xx_workarounds_lora_disable_sx1276_compatibility_mode
*/
lr20xx_status_t lr20xx_workarounds_lora_sx1276_compatibility_mode_store_retention_mem( const void* context,
uint8_t slot );
/* Enable SX1276 freq-hopping compatibility; call after lr20xx_radio_lora_set_freq_hop */
/**
* @brief Enable the SX1276 compatibility mode for LoRa intra-packet frequency hopping
*
* If the LoRa intra-packet frequency hopping compatible with SX1276 is required, this function must be called after
* @ref lr20xx_radio_lora_set_freq_hop.
*
* @param context Chip implementation context
*
* @return Operation status
*
* @see lr20xx_radio_lora_set_freq_hop, lr20xx_workarounds_lora_freq_hop_disable_sx1276_compatibility_mode,
* lr20xx_workarounds_lora_freq_hop_sx1276_compatibility_mode_store_retention_mem
*/
lr20xx_status_t lr20xx_workarounds_lora_freq_hop_enable_sx1276_compatibility_mode( const void* context );
/* Disable SX1276 freq-hopping compatibility */
/**
* @brief Disable the SX1276 compatibility mode for LoRa intra-packet frequency hopping
*
* @param context Chip implementation context
*
* @return Operation status
*
* @see lr20xx_radio_lora_set_freq_hop, lr20xx_workarounds_lora_freq_hop_enable_sx1276_compatibility_mode,
* lr20xx_workarounds_lora_freq_hop_sx1276_compatibility_mode_store_retention_mem
*/
lr20xx_status_t lr20xx_workarounds_lora_freq_hop_disable_sx1276_compatibility_mode( const void* context );
/* Persist SX1276 freq-hopping compatibility register across sleep; slot in [0:31] */
/**
* @brief Store the SX1276 compatibility mode for LoRa intra-packet frequency hopping in retention memory
*
* Calling this function allows to store the SX1276 LoRa intra-packet frequency hopping compatible state during sleep
* mode. This helper function internally calls @ref lr20xx_system_add_register_to_retention_mem with the appropriate
* register address.
*
* @param context Chip implementation context
* @param slot Index in the storage list. Allowed values [0:31]
*
* @return Operation status
*
* @see lr20xx_system_add_register_to_retention_mem, lr20xx_workarounds_lora_freq_hop_enable_sx1276_compatibility_mode,
* lr20xx_workarounds_lora_freq_hop_disable_sx1276_compatibility_mode
*/
lr20xx_status_t lr20xx_workarounds_lora_freq_hop_sx1276_compatibility_mode_store_retention_mem( const void* context,
uint8_t slot );
/*
* Override OOK detection threshold. The default chip-computed value may be too conservative, raising PER.
* Set to the noise floor (from lr20xx_radio_common_get_rssi_inst) if it exceeds the default.
* Call after lr20xx_radio_ook_set_modulation_params. threshold_level_db in dBm.
/**
* @brief Override the OOK detection threshold level
*
* The OOK detection threshold level is automatically computed by the LR20xx depending on the modulation parameters.
* However the computed value may be too conservative which increase the packet error rate.
* The detection threshold level can be therefore modified with this function. The threshold to provide is typically the
* noise level returned by @ref lr20xx_radio_common_get_rssi_inst using the same modulation parameters, if it is higher
* than the LR20xx default computed value.
*
* Refer to @ref lr20xx_workarounds_ook_get_default_detection_threshold_level to obtain the default computed values
* depending on modulation bandwidth.
*
* This function should be called after @ref lr20xx_radio_ook_set_modulation_params.
*
* @param context Chip implementation context
* @param threshold_level_db The threshold level to set, in dB
*
* @return Operation status
*
* @see lr20xx_radio_ook_set_modulation_params, lr20xx_radio_common_get_rssi_inst,
* lr20xx_workarounds_ook_get_default_detection_threshold_level
*/
lr20xx_status_t lr20xx_workarounds_ook_set_detection_threshold_level( const void* context, int16_t threshold_level_db );
/*
* Return default OOK detection threshold (dBm) for the given bandwidth.
* Returns 0 for unknown bandwidth values.
/**
* @brief Helper function that returns default OOK detection threshold level
*
* This helper function helps to determine if the workaround @ref lr20xx_workarounds_ook_set_detection_threshold_level
* is to be applied.
*
* @param bw The bandwidth for which the detection threshold is to be computed
*
* @return The default OOK detection threshold level, or 0 if the bandwidth @p bw is unknown
*
* @see lr20xx_workarounds_ook_set_detection_threshold_level
*
*/
int16_t lr20xx_workarounds_ook_get_default_detection_threshold_level( lr20xx_radio_fsk_common_bw_t bw );
/*
* Truncate internal PLL frequency to the nearest 122Hz multiple for RTToF accuracy.
* Call after lr20xx_radio_common_set_rf_freq for RTToF ranging; adjusts RF freq by 122Hz.
*/
lr20xx_status_t lr20xx_workarounds_rttof_truncate_pll_freq_step( const void* context );
/*
* Correct RTToF raw RSSI values using gain/offset read from hardware registers.
* raw = -(rssi_dB * 2); rssi_dB = -(raw / 2).
* rssi2_raw_fixed may be null for single-RSSI (normal) results.
*/
lr20xx_status_t lr20xx_workarounds_rttof_rssi_computation( const void* context, uint8_t rssi1_raw_value,
uint8_t rssi2_raw_value, uint8_t* rssi1_raw_fixed,
uint8_t* rssi2_raw_fixed );
/*
* Reset DCDC switcher to default timing.
* Required after lr20xx_radio_common_set_pkt_type when: sub-GHz RX + DCDC regulator mode.
*/
lr20xx_status_t lr20xx_workarounds_dcdc_reset( const void* context );
/*
* Configure DCDC switcher timing based on current RX path.
* Required after any of: fsk/flrc/ook/lora set_modulation_params, z_wave_set_params, set_rx_path;
* when: sub-GHz RX + DCDC regulator mode.
*/
lr20xx_status_t lr20xx_workarounds_dcdc_configure( const void* context );
/* Persist DCDC switcher register across sleep; slot in [0:31] */
lr20xx_status_t lr20xx_workarounds_dcdc_store_retention_mem( const void* context, uint8_t slot );
/*
* Reduce RTToF result deviation on fractional bandwidths (BW_812/406/203/101).
* Call after lr20xx_radio_lora_set_modulation_params; reset by subsequent set_modulation_params.
* is_manager: true for RTToF manager role, false for subordinate.
/**
* @brief Apply workaround to reduce standard deviation of RTToF results with fractional bandwidths
*
* This workaround reduces the standard deviation of observed RTToF result on the following bandwiths:
* - @ref LR20XX_RADIO_LORA_BW_812
* - @ref LR20XX_RADIO_LORA_BW_406
* - @ref LR20XX_RADIO_LORA_BW_203
* - @ref LR20XX_RADIO_LORA_BW_101
* The workaround must be called only on these bandwidths, after calling @ref lr20xx_radio_lora_set_modulation_params.
*
* Note that a call to @ref lr20xx_radio_lora_set_modulation_params reset the changes executed by this workaround.
*
* @param context Chip implementation context
* @param is_manager True if the device operate as manager, false if it operates as subordinate
*
* @return Operation status
*
* @see lr20xx_radio_lora_set_modulation_params
*/
lr20xx_status_t lr20xx_workarounds_rttof_results_deviation( const void* context, bool is_manager );
/* Persist RTToF deviation workaround registers (two slots) across sleep; slots in [0:31] */
/**
* @brief Store the registers for RTToF results deviation workaround in retention memory
*
* Calling this function allows to store the RTToF results deviation workaround registers during sleep mode. This helper
* function internally calls @ref lr20xx_system_add_register_to_retention_mem with the appropriate register address.
*
* The @ref lr20xx_workarounds_rttof_results_deviation workaround addresses two registers, hence the two configurable
* slots.
*
* @param context Chip implementation context
* @param slot_1 Index in the storage list. Allowed values [0:31]
* @param slot_2 Index in the storage list. Allowed values [0:31]
*
* @return Operation status
*
* @see lr20xx_system_add_register_to_retention_mem, lr20xx_workarounds_rttof_results_deviation
*/
lr20xx_status_t lr20xx_workarounds_rttof_results_deviation_store_retention_mem( const void* context, uint8_t slot_1,
uint8_t slot_2 );
/* Enable RTToF extended-mode workaround; required when using LR20XX_RTTOF_MODE_EXTENDED */
lr20xx_status_t lr20xx_workarounds_rttof_extended_stuck_second_request_enable( const void* context );
/*!
* @brief Workaround helper to configure FIFO events and threshold levels with 1024-byte Tx/Rx FiFos
*
* This workaround wraps @ref lr20xx_radio_fifo_cfg_irq when using 1024-byte Rx/Tx FiFos to allow settings @p
* tx_fifo_low_threshold and @p rx_fifo_low_threshold to value superior to 256.
*
* This workaround configures registers that are not maintained in memory during sleep mode. Call @ref
* lr20xx_workarounds_1024_byte_fifo_cfg_irq_store_retention_mem to register these registers as maintained during sleep
* mode.
*
* @param [in] context Chip implementation context
* @param [in] rx_fifo_irq_enable FIFO events triggering an interrupt in Rx
* @param [in] tx_fifo_irq_enable FIFO events triggering an interrupt in Tx
* @param [in] rx_fifo_high_threshold Rx FIFO threshold above which an interrupt (if
* LR20XX_RADIO_FIFO_FLAG_THRESHOLD_HIGH is enabled) is triggered
* @param [in] tx_fifo_low_threshold Tx FIFO threshold below which an interrupt (if LR20XX_RADIO_FIFO_FLAG_THRESHOLD_LOW
* is enabled) is triggered
* @param [in] rx_fifo_low_threshold Rx FIFO threshold below which an interrupt (if LR20XX_RADIO_FIFO_FLAG_THRESHOLD_LOW
* is enabled) is triggered
* @param [in] tx_fifo_high_threshold Tx FIFO threshold above which an interrupt (if
* LR20XX_RADIO_FIFO_FLAG_THRESHOLD_HIGH is enabled) is triggered
*
* @returns Operation status
*
* @see lr20xx_radio_fifo_cfg_irq, lr20xx_radio_fifo_configure_1024_byte_tx_fifo,
* lr20xx_radio_fifo_configure_1024_byte_rx_fifo
*/
lr20xx_status_t lr20xx_workarounds_1024_byte_fifo_cfg_irq(
const void* context, lr20xx_radio_fifo_flag_t rx_fifo_irq_enable, lr20xx_radio_fifo_flag_t tx_fifo_irq_enable,
uint16_t rx_fifo_high_threshold, uint16_t tx_fifo_low_threshold, uint16_t rx_fifo_low_threshold,
uint16_t tx_fifo_high_threshold );
/* Disable RTToF extended-mode workaround when switching back to LR20XX_RTTOF_MODE_NORMAL */
lr20xx_status_t lr20xx_workarounds_rttof_extended_stuck_second_request_disable( const void* context );
/* Persist RTToF extended-mode workaround register across sleep; slot in [0:31] */
lr20xx_status_t lr20xx_workarounds_rttof_extended_stuck_second_request_store_retention_mem( const void* context,
uint8_t slot );
/**
* @brief Store the registers to configure the 1024 bytes Tx/Rx FiFos threshold related IRQs in retention memory
*
* Calling this function allows to store the workaround registers for IRQ FiFo configuration with 1024-byte Tx/Rx FiFos
* during sleep mode. This helper function internally calls @ref lr20xx_system_add_register_to_retention_mem with the
* appropriate register address.
*
* @param [in] context Chip implementation context
* @param [in] retention_slot_rx_thresholds Retention memory slot to store Rx FiFo thresholds
* @param [in] retention_slot_tx_thresholds Retention memory slot to store Tx FiFo thresholds
*
* @return Operation status
*
* @see lr20xx_system_add_register_to_retention_mem, lr20xx_workarounds_1024_byte_fifo_cfg_irq
*/
lr20xx_status_t lr20xx_workarounds_1024_byte_fifo_cfg_irq_store_retention_mem( const void* context,
uint8_t retention_slot_rx_thresholds,
uint8_t retention_slot_tx_thresholds );
#ifdef __cplusplus
}
@@ -3,11 +3,11 @@
zephyr_library()
zephyr_library_compile_definitions(LR20XX_DISABLE_WARNINGS)
# We run in LDO mode (not DCDC) disable automatic DCDC workarounds
# that the SDK injects after set_pkt_type, set_rx_path, set_modulation_params.
# Per lr20xx_workarounds.h, these are only needed when REG_MODE_DCDC is used.
zephyr_library_compile_definitions(LR20XX_WORKAROUNDS_DISABLE_AUTOMATIC_DCDC_RESET)
zephyr_library_compile_definitions(LR20XX_WORKAROUNDS_DISABLE_AUTOMATIC_DCDC_CONFIGURE)
# The two LR20XX_WORKAROUNDS_DISABLE_AUTOMATIC_DCDC_* defines that used to live
# here are gone: SDK v2.0.2 deleted lr20xx_workarounds_dcdc_reset/_configure and
# the macros that injected them after set_pkt_type / set_rx_path /
# set_modulation_params. That workaround now lives in the Patch RAM, which this
# driver loads on every reset. Nothing references the defines any more.
zephyr_library_sources(lr20xx_lora.c)
@@ -20,6 +20,12 @@ zephyr_library_sources(${LR20XX_SDK_DIR}/lr20xx_system.c)
zephyr_library_sources(${LR20XX_SDK_DIR}/lr20xx_regmem.c)
zephyr_library_sources(${LR20XX_SDK_DIR}/lr20xx_workarounds.c)
zephyr_library_sources(${LR20XX_SDK_DIR}/lr20xx_driver_version.c)
# Firmware Patch RAM loader (DS rev 2.1 section 22.3). The image itself lives in
# lr20xx_pram_lr2021.h, included by lr20xx_lora.c. lr20xx_pram_load.c is
# deliberately not vendored: it only dispatches between the LR2021 and
# LR2012/LR2022 images, and pulling it in would drag 2 KB of LR20x2 patch data
# into a driver that binds to semtech,lr2021 only.
zephyr_library_sources(${LR20XX_SDK_DIR}/lr20xx_patch.c)
zephyr_library_include_directories(${LR20XX_SDK_DIR})
zephyr_library_add_dependencies(offsets_h)
@@ -28,6 +28,11 @@
#include "lr20xx_system_types.h"
#include "lr20xx_workarounds.h"
#include "lr20xx_regmem.h"
#include "lr20xx_patch.h"
/* Defines the PRAM image itself (pram_lr2021 / pram_lr2021_size). In C these
* are const objects at file scope and therefore have external linkage, so this
* header must be included from exactly one translation unit this one. */
#include "lr20xx_pram_lr2021.h"
LOG_MODULE_REGISTER(lr20xx_lora, CONFIG_LORA_LOG_LEVEL);
@@ -384,6 +389,80 @@ static void lr20xx_get_pa_cfg_for_power(int8_t power_dbm,
static lr20xx_status_t lr20xx_calibrate_front_end(void *ctx, uint32_t freq_hz);
/* ── Firmware Patch RAM (PRAM) ──────────────────────────────────────── */
/* Base address the patch image is written to — DS §22.3.1, and the same value
* lr20xx_patch.c uses internally (it does not export it). */
#define LR20XX_PRAM_BASE_ADDRESS 0x801000
/* Load and activate the firmware Patch RAM.
*
* DS §22.3: "using the chip without the PRAM can create performance issues and
* unexpected bugs. The use of the PRAM is therefore highly recommended", and
* §22: "Most of the workarounds are implemented in the Firmware Patch RAM".
* Semtech's own driver confirms the relationship v2.0.2 added PRAM support and
* deleted its BLE, RTToF and DC-DC workaround functions in the same release,
* because the patch supersedes them.
*
* The image is volatile: lost on reset and on cold start, preserved by sleep
* with retention (§22.3). Every sleep this driver issues sets retention
* (lr20xx_reset_agc), and duty-cycle sleep is retention by definition (§6.3.8),
* so the reset paths are the only places it has to be (re)loaded. Costs 2240
* bytes of flash and +80 nA of retention sleep current.
*
* Best-effort: a chip without the patch still works, so a failure here is a
* warning, not a reason to fail init. */
static void lr20xx_load_pram(struct lr20xx_data *data)
{
void *ctx = &data->hal_ctx;
lr20xx_system_version_t chip = { 0 };
lr20xx_patch_version_t pram = { 0 };
lr20xx_status_t rc;
/* DS §22.3.1: "There is one dedicated to the LR2021 and another one for
* the LR2012/LR2022. The GetVersion(...) API indicates which PRAM is
* needed." Per DS Table 6-40 the LR2021 answers 0x01/0x18; the other two
* answer 0x02/0x00 and want lr20xx_pram_lr20x2.h, which is not vendored
* because this driver only binds to semtech,lr2021. Read the version
* here rather than taking it from the caller so both reset paths get the
* same check. */
if (lr20xx_system_get_version(ctx, &chip) != LR20XX_STATUS_OK) {
LOG_WRN("PRAM: get_version failed — skipping patch load");
return;
}
if (chip.major != 0x01 || chip.minor != 0x18) {
LOG_WRN("PRAM: chip reports FW %u.%u, not the LR2021's 1.24 — "
"no matching patch image vendored, skipping",
chip.major, chip.minor);
return;
}
rc = lr20xx_patch_load_pram(ctx, LR20XX_PRAM_BASE_ADDRESS, pram_lr2021,
pram_lr2021_size);
if (rc != LR20XX_STATUS_OK) {
LOG_ERR("PRAM: load failed (rc=%d) — running unpatched", rc);
return;
}
rc = lr20xx_patch_enable_pram(ctx);
if (rc != LR20XX_STATUS_OK) {
LOG_ERR("PRAM: enable failed (rc=%d) — running unpatched", rc);
return;
}
/* Reads back the magic word at 0x800FF8 (DS §22.3.2) — the only proof
* the chip actually took the patch, so it is worth the two extra reads
* on a path that runs once per reset. */
if (lr20xx_patch_get_version(ctx, &pram) != LR20XX_STATUS_OK ||
!pram.is_pram_loaded) {
LOG_ERR("PRAM: magic word absent after load — running unpatched");
return;
}
LOG_INF("PRAM loaded: type=0x%02x version=0x%02x (%u words)",
pram.pram_type, pram.pram_version, pram_lr2021_size);
}
/* ── Hardware reset (BUSY stuck recovery) ───────────────────────────── */
static void lr20xx_hardware_reset(struct lr20xx_data *data,
@@ -395,7 +474,15 @@ static void lr20xx_hardware_reset(struct lr20xx_data *data,
lr20xx_hal_reset(ctx);
/* SIMO workaround skipped — LDO mode (see DS §22.6) */
/* The reset wiped the patch — DS §22.3: "The PRAM is lost after a reset
* or a cold start", and §22.3.1 requires it be reloaded "after a reset,
* as part of the reset sequence". */
lr20xx_load_pram(data);
/* SIMO workaround skipped — LDO mode. (The citation here used to be
* "DS §22.6"; rev 2.1 has no such section §22 ends at 22.3. The
* conclusion still holds via Table 6-26: simo_usage 0x00 SIMO_OFF is the
* reset default and we never issue SetRegMode.) */
if (cfg->tcxo_voltage_mv > 0) {
/* Timeout in RTC ticks (30.52 µs/tick) */
@@ -1992,6 +2079,13 @@ static int lr20xx_hw_init(struct lr20xx_data *data,
ver.major, ver.minor);
}
/* Patch the firmware before anything is configured or calibrated — DS
* §22.3.1: load "after a reset, as part of the reset sequence". The
* TCXOXTAL fallback below re-enters this function, which resets the chip
* again and so reaches this point again; that is required, since the
* reset drops the patch. */
lr20xx_load_pram(data);
DUMP_CHIP_STATE(data, "post-reset");
/* SIMO DC-DC workaround REMOVED — datasheet §22.6 says it's only