diff --git a/.gitignore b/.gitignore index c20d2a2..fe11e5b 100644 --- a/.gitignore +++ b/.gitignore @@ -140,3 +140,4 @@ handover_thinknode_m9.md # Vendor reference docs (datasheets, errata). Local only — not ours to redistribute. /datasheets/ +LR2021_AUDIT_INDEX.md diff --git a/zephcore/adapters/radio/lr20xx/LICENSE.txt b/zephcore/adapters/radio/lr20xx/LICENSE.txt new file mode 100644 index 0000000..292ef9b --- /dev/null +++ b/zephcore/adapters/radio/lr20xx/LICENSE.txt @@ -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. diff --git a/zephcore/adapters/radio/lr20xx/lr20xx_driver_version.h b/zephcore/adapters/radio/lr20xx/lr20xx_driver_version.h index 708cd96..0a9483a 100644 --- a/zephcore/adapters/radio/lr20xx/lr20xx_driver_version.h +++ b/zephcore/adapters/radio/lr20xx/lr20xx_driver_version.h @@ -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" /* * ----------------------------------------------------------------------------- diff --git a/zephcore/adapters/radio/lr20xx/lr20xx_hal.h b/zephcore/adapters/radio/lr20xx/lr20xx_hal.h index d922b46..4bf1f1a 100644 --- a/zephcore/adapters/radio/lr20xx/lr20xx_hal.h +++ b/zephcore/adapters/radio/lr20xx/lr20xx_hal.h @@ -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; /* diff --git a/zephcore/adapters/radio/lr20xx/lr20xx_patch.c b/zephcore/adapters/radio/lr20xx/lr20xx_patch.c new file mode 100644 index 0000000..d86dce6 --- /dev/null +++ b/zephcore/adapters/radio/lr20xx/lr20xx_patch.c @@ -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 // 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 ------------------------------------------------------------------ */ diff --git a/zephcore/adapters/radio/lr20xx/lr20xx_patch.h b/zephcore/adapters/radio/lr20xx/lr20xx_patch.h new file mode 100644 index 0000000..3081625 --- /dev/null +++ b/zephcore/adapters/radio/lr20xx/lr20xx_patch.h @@ -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 +#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 ------------------------------------------------------------------ */ diff --git a/zephcore/adapters/radio/lr20xx/lr20xx_patch_types.h b/zephcore/adapters/radio/lr20xx/lr20xx_patch_types.h new file mode 100644 index 0000000..371dd1e --- /dev/null +++ b/zephcore/adapters/radio/lr20xx/lr20xx_patch_types.h @@ -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 +#include + +/* + * ----------------------------------------------------------------------------- + * --- 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 ------------------------------------------------------------------ */ diff --git a/zephcore/adapters/radio/lr20xx/lr20xx_pram_lr2021.h b/zephcore/adapters/radio/lr20xx/lr20xx_pram_lr2021.h new file mode 100644 index 0000000..6549547 --- /dev/null +++ b/zephcore/adapters/radio/lr20xx/lr20xx_pram_lr2021.h @@ -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 + +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 diff --git a/zephcore/adapters/radio/lr20xx/lr20xx_radio_common.c b/zephcore/adapters/radio/lr20xx/lr20xx_radio_common.c index a8b979d..08771c2 100644 --- a/zephcore/adapters/radio/lr20xx/lr20xx_radio_common.c +++ b/zephcore/adapters/radio/lr20xx/lr20xx_radio_common.c @@ -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 ) diff --git a/zephcore/adapters/radio/lr20xx/lr20xx_radio_common.h b/zephcore/adapters/radio/lr20xx/lr20xx_radio_common.h index 311a6f7..cc156f9 100644 --- a/zephcore/adapters/radio/lr20xx/lr20xx_radio_common.h +++ b/zephcore/adapters/radio/lr20xx/lr20xx_radio_common.h @@ -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: + * + * + * + * + *
Special values Meaning
0x000000 RX single - transceiver stays in RX mode until a packet is received
0xFFFFFF RX continuous - transceiver stays in RX mode even after reception of a packet
+ * + * @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 ); diff --git a/zephcore/adapters/radio/lr20xx/lr20xx_radio_fifo.c b/zephcore/adapters/radio/lr20xx/lr20xx_radio_fifo.c index 618f8f5..e010221 100644 --- a/zephcore/adapters/radio/lr20xx/lr20xx_radio_fifo.c +++ b/zephcore/adapters/radio/lr20xx/lr20xx_radio_fifo.c @@ -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 -------------------------------------------- diff --git a/zephcore/adapters/radio/lr20xx/lr20xx_radio_fifo.h b/zephcore/adapters/radio/lr20xx/lr20xx_radio_fifo.h index 3f53474..fc81e18 100644 --- a/zephcore/adapters/radio/lr20xx/lr20xx_radio_fifo.h +++ b/zephcore/adapters/radio/lr20xx/lr20xx_radio_fifo.h @@ -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 diff --git a/zephcore/adapters/radio/lr20xx/lr20xx_radio_flrc.h b/zephcore/adapters/radio/lr20xx/lr20xx_radio_flrc.h index caff9bf..dc1ed43 100644 --- a/zephcore/adapters/radio/lr20xx/lr20xx_radio_flrc.h +++ b/zephcore/adapters/radio/lr20xx/lr20xx_radio_flrc.h @@ -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 ); diff --git a/zephcore/adapters/radio/lr20xx/lr20xx_radio_flrc_types.h b/zephcore/adapters/radio/lr20xx/lr20xx_radio_flrc_types.h index e59813d..ee23b6a 100644 --- a/zephcore/adapters/radio/lr20xx/lr20xx_radio_flrc_types.h +++ b/zephcore/adapters/radio/lr20xx/lr20xx_radio_flrc_types.h @@ -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; /** diff --git a/zephcore/adapters/radio/lr20xx/lr20xx_radio_lora.c b/zephcore/adapters/radio/lr20xx/lr20xx_radio_lora.c index 6e1ac1c..4220d4a 100644 --- a/zephcore/adapters/radio/lr20xx/lr20xx_radio_lora.c +++ b/zephcore/adapters/radio/lr20xx/lr20xx_radio_lora.c @@ -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: diff --git a/zephcore/adapters/radio/lr20xx/lr20xx_radio_lora.h b/zephcore/adapters/radio/lr20xx/lr20xx_radio_lora.h index 1bfae61..2badeb4 100644 --- a/zephcore/adapters/radio/lr20xx/lr20xx_radio_lora.h +++ b/zephcore/adapters/radio/lr20xx/lr20xx_radio_lora.h @@ -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 SX126x/LR11xx/LR20xx syncword 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 LR20xx syncword SX127x compatibility + * 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 ); diff --git a/zephcore/adapters/radio/lr20xx/lr20xx_radio_lora_types.h b/zephcore/adapters/radio/lr20xx/lr20xx_radio_lora_types.h index d3ed6b5..18fd9ee 100644 --- a/zephcore/adapters/radio/lr20xx/lr20xx_radio_lora_types.h +++ b/zephcore/adapters/radio/lr20xx/lr20xx_radio_lora_types.h @@ -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; /** diff --git a/zephcore/adapters/radio/lr20xx/lr20xx_radio_ook.h b/zephcore/adapters/radio/lr20xx/lr20xx_radio_ook.h index c86924b..40ee1c2 100644 --- a/zephcore/adapters/radio/lr20xx/lr20xx_radio_ook.h +++ b/zephcore/adapters/radio/lr20xx/lr20xx_radio_ook.h @@ -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 ); diff --git a/zephcore/adapters/radio/lr20xx/lr20xx_radio_ook_types.h b/zephcore/adapters/radio/lr20xx/lr20xx_radio_ook_types.h index f64cbf2..7ed94a9 100644 --- a/zephcore/adapters/radio/lr20xx/lr20xx_radio_ook_types.h +++ b/zephcore/adapters/radio/lr20xx/lr20xx_radio_ook_types.h @@ -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 { diff --git a/zephcore/adapters/radio/lr20xx/lr20xx_regmem.c b/zephcore/adapters/radio/lr20xx/lr20xx_regmem.c index a2348c8..74e82bb 100644 --- a/zephcore/adapters/radio/lr20xx/lr20xx_regmem.c +++ b/zephcore/adapters/radio/lr20xx/lr20xx_regmem.c @@ -37,6 +37,7 @@ * --- DEPENDENCIES ------------------------------------------------------------ */ +#include #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 ------------------------------------------------------------------ */ diff --git a/zephcore/adapters/radio/lr20xx/lr20xx_regmem.h b/zephcore/adapters/radio/lr20xx/lr20xx_regmem.h index f10b509..14ca058 100644 --- a/zephcore/adapters/radio/lr20xx/lr20xx_regmem.h +++ b/zephcore/adapters/radio/lr20xx/lr20xx_regmem.h @@ -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. * diff --git a/zephcore/adapters/radio/lr20xx/lr20xx_status.h b/zephcore/adapters/radio/lr20xx/lr20xx_status.h index 8fa8f57..e9a9b69 100644 --- a/zephcore/adapters/radio/lr20xx/lr20xx_status.h +++ b/zephcore/adapters/radio/lr20xx/lr20xx_status.h @@ -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; /* diff --git a/zephcore/adapters/radio/lr20xx/lr20xx_system.c b/zephcore/adapters/radio/lr20xx/lr20xx_system.c index ea32076..4ea92a1 100644 --- a/zephcore/adapters/radio/lr20xx/lr20xx_system.c +++ b/zephcore/adapters/radio/lr20xx/lr20xx_system.c @@ -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 ), diff --git a/zephcore/adapters/radio/lr20xx/lr20xx_system.h b/zephcore/adapters/radio/lr20xx/lr20xx_system.h index b0fd21f..062ce47 100644 --- a/zephcore/adapters/radio/lr20xx/lr20xx_system.h +++ b/zephcore/adapters/radio/lr20xx/lr20xx_system.h @@ -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 DIO7–DIO11. - * 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 ); diff --git a/zephcore/adapters/radio/lr20xx/lr20xx_system_types.h b/zephcore/adapters/radio/lr20xx/lr20xx_system_types.h index 4ff1622..f11107a 100644 --- a/zephcore/adapters/radio/lr20xx/lr20xx_system_types.h +++ b/zephcore/adapters/radio/lr20xx/lr20xx_system_types.h @@ -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; /** diff --git a/zephcore/adapters/radio/lr20xx/lr20xx_workarounds.c b/zephcore/adapters/radio/lr20xx/lr20xx_workarounds.c index 44f973b..31cfbf2 100644 --- a/zephcore/adapters/radio/lr20xx/lr20xx_workarounds.c +++ b/zephcore/adapters/radio/lr20xx/lr20xx_workarounds.c @@ -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 ------------------------------------------------------------------ */ diff --git a/zephcore/adapters/radio/lr20xx/lr20xx_workarounds.h b/zephcore/adapters/radio/lr20xx/lr20xx_workarounds.h index 9cbfb8c..b47d8c4 100644 --- a/zephcore/adapters/radio/lr20xx/lr20xx_workarounds.h +++ b/zephcore/adapters/radio/lr20xx/lr20xx_workarounds.h @@ -48,31 +48,13 @@ extern "C" { #include #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 } diff --git a/zephcore/patches/zephyr-new/drivers/lora/lr20xx/CMakeLists.txt b/zephcore/patches/zephyr-new/drivers/lora/lr20xx/CMakeLists.txt index d47fa07..962649f 100644 --- a/zephcore/patches/zephyr-new/drivers/lora/lr20xx/CMakeLists.txt +++ b/zephcore/patches/zephyr-new/drivers/lora/lr20xx/CMakeLists.txt @@ -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) diff --git a/zephcore/patches/zephyr-new/drivers/lora/lr20xx/lr20xx_lora.c b/zephcore/patches/zephyr-new/drivers/lora/lr20xx/lr20xx_lora.c index 35ec78f..02dbf2a 100644 --- a/zephcore/patches/zephyr-new/drivers/lora/lr20xx/lr20xx_lora.c +++ b/zephcore/patches/zephyr-new/drivers/lora/lr20xx/lr20xx_lora.c @@ -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 + * TCXO→XTAL 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