Compare commits
10 Commits
f8836dd1b1
..
main
| Author | SHA1 | Date | |
|---|---|---|---|
| e6f96ea0e3 | |||
| b125dd33b9 | |||
| d382bdfd1e | |||
| efc6e17ed0 | |||
| 1c3626d58b | |||
| 4fb41a3211 | |||
| d4709da971 | |||
| 32a0c80ab0 | |||
| d8db9e1eb0 | |||
| ce56757dac |
@@ -0,0 +1,25 @@
|
||||
# C++ specific configuration (akin to Google's C++ style)
|
||||
# https://clang.llvm.org/docs/ClangFormatStyleOptions.html#adding-additional-style-options
|
||||
---
|
||||
Language: Cpp
|
||||
BasedOnStyle: LLVM
|
||||
UseTab: ForContinuationAndIndentation
|
||||
IndentWidth: 4
|
||||
TabWidth: 4
|
||||
AccessModifierOffset: -4
|
||||
ColumnLimit: 0
|
||||
NamespaceIndentation: Inner
|
||||
FixNamespaceComments: false
|
||||
AllowShortIfStatementsOnASingleLine: WithoutElse
|
||||
AllowShortLoopsOnASingleLine: true
|
||||
AllowShortBlocksOnASingleLine: Empty
|
||||
IndentCaseLabels: false
|
||||
SortIncludes: Never
|
||||
AlignConsecutiveMacros: AcrossEmptyLines
|
||||
AlignConsecutiveAssignments: Consecutive
|
||||
BreakStringLiterals: true
|
||||
LineEnding: LF
|
||||
MaxEmptyLinesToKeep: 2
|
||||
BreakBeforeBraces: Attach
|
||||
InsertBraces: true
|
||||
BreakAfterAttributes: Always
|
||||
@@ -0,0 +1 @@
|
||||
.DS_Store
|
||||
+45
-2
@@ -1,9 +1,9 @@
|
||||
DT_COMPAT_SEMTECH_LLCC68 := "semtech,llcc68"
|
||||
DT_COMPAT_SEMTECH_LLCC68_WEIHUA := "semtech,llcc68-weihua"
|
||||
|
||||
config LLCC68
|
||||
bool "Semtech LLCC68 LoRa Radio Driver"
|
||||
depends on SPI && GPIO
|
||||
default $(dt_compat_enabled,$(DT_COMPAT_SEMTECH_LLCC68))
|
||||
default $(dt_compat_enabled,$(DT_COMPAT_SEMTECH_LLCC68_WEIHUA))
|
||||
help
|
||||
Enable the Semtech LLCC68 LoRa Radio Driver.
|
||||
|
||||
@@ -14,6 +14,17 @@ config LLCC68_INIT_PRIORITY
|
||||
The priority of the LLCC68 initialization. Lower numbers indicate
|
||||
higher priority.
|
||||
|
||||
config LLCC68_MAX_PAYLOAD_LENGTH
|
||||
int "LLCC68 maximum payload length"
|
||||
default 128
|
||||
range 1 255
|
||||
help
|
||||
Maximum radio payload length accepted by the LLCC68 driver.
|
||||
|
||||
The LLCC68 packet length fields support up to 255 bytes. Keep this
|
||||
lower when the application has a known payload ceiling to reduce RAM
|
||||
used by the driver's SPI staging buffers.
|
||||
|
||||
config LLCC68_ALWAYS_USE_SX1262_HIGH_PA
|
||||
bool "LLCC68 Always Use SX1262 High Power Amplifier"
|
||||
default y
|
||||
@@ -21,6 +32,38 @@ config LLCC68_ALWAYS_USE_SX1262_HIGH_PA
|
||||
When enabled, the LLCC68/SX1262/SX1261 driver always chooses high
|
||||
power amplifier settings instead of selecting them from chip version.
|
||||
|
||||
choice LLCC68_RF_SWITCH_DEFAULT
|
||||
prompt "Default LLCC68 RF switch mode"
|
||||
default LLCC68_RF_SWITCH_DEFAULT_AUTO
|
||||
help
|
||||
Default RF switch mode for LLCC68 devicetree nodes that do not set
|
||||
rf-switch-mode.
|
||||
|
||||
config LLCC68_RF_SWITCH_DEFAULT_AUTO
|
||||
bool "Auto"
|
||||
help
|
||||
Preserve legacy behavior: use complementary GPIO control when both
|
||||
tx-enable-gpios and rx-enable-gpios are present, otherwise disable RF
|
||||
switch control.
|
||||
|
||||
config LLCC68_RF_SWITCH_DEFAULT_NONE
|
||||
bool "None"
|
||||
help
|
||||
Disable RF switch control unless rf-switch-mode is set in devicetree.
|
||||
|
||||
config LLCC68_RF_SWITCH_DEFAULT_GPIO_COMPLEMENTARY
|
||||
bool "TXEN/RXEN complementary GPIO"
|
||||
help
|
||||
Use MCU GPIOs for complementary TXEN/RXEN RF switch control by default.
|
||||
|
||||
config LLCC68_RF_SWITCH_DEFAULT_DIO2_SINGLE
|
||||
bool "DIO2 single-pin"
|
||||
help
|
||||
Use LLCC68 DIO2 RF switch control by default. DIO2 drives TXEN, while
|
||||
RXEN is held active externally or by rx-enable-gpios.
|
||||
|
||||
endchoice
|
||||
|
||||
module = LLCC68
|
||||
module-str = llcc68
|
||||
|
||||
|
||||
+62
-20
@@ -1,10 +1,34 @@
|
||||
#include "llcc68_raw.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <zephyr/devicetree.h>
|
||||
#include <zephyr/sys_clock.h>
|
||||
#include <zephyr/sys/util.h>
|
||||
|
||||
#define DT_DRV_COMPAT semtech_llcc68_weihua
|
||||
|
||||
#define LLCC68_AUTO_RF_SWITCH_MODE(inst) \
|
||||
COND_CODE_1(DT_INST_NODE_HAS_PROP(inst, tx_enable_gpios), \
|
||||
(COND_CODE_1(DT_INST_NODE_HAS_PROP(inst, rx_enable_gpios), \
|
||||
(LLCC68_RF_SWITCH_GPIO_COMPLEMENTARY), (LLCC68_RF_SWITCH_NONE))), \
|
||||
(LLCC68_RF_SWITCH_NONE))
|
||||
|
||||
#if defined(CONFIG_LLCC68_RF_SWITCH_DEFAULT_GPIO_COMPLEMENTARY)
|
||||
#define LLCC68_DEFAULT_RF_SWITCH_MODE(inst) LLCC68_RF_SWITCH_GPIO_COMPLEMENTARY
|
||||
#elif defined(CONFIG_LLCC68_RF_SWITCH_DEFAULT_DIO2_SINGLE)
|
||||
#define LLCC68_DEFAULT_RF_SWITCH_MODE(inst) LLCC68_RF_SWITCH_DIO2_SINGLE
|
||||
#elif defined(CONFIG_LLCC68_RF_SWITCH_DEFAULT_NONE)
|
||||
#define LLCC68_DEFAULT_RF_SWITCH_MODE(inst) LLCC68_RF_SWITCH_NONE
|
||||
#else
|
||||
#define LLCC68_DEFAULT_RF_SWITCH_MODE(inst) LLCC68_AUTO_RF_SWITCH_MODE(inst)
|
||||
#endif
|
||||
|
||||
#define LLCC68_RF_SWITCH_MODE(inst) \
|
||||
DT_ENUM_IDX_OR(DT_DRV_INST(inst), rf_switch_mode, LLCC68_DEFAULT_RF_SWITCH_MODE(inst))
|
||||
|
||||
#define LLCC68_SPI_CS_DELAY_US(inst) \
|
||||
DIV_ROUND_UP(DT_INST_PROP(inst, spi_cs_setup_delay_ns), NSEC_PER_USEC)
|
||||
|
||||
static void dio1_irq_trampoline(const struct device *port, struct gpio_callback *cb, uint32_t pins) {
|
||||
ARG_UNUSED(port);
|
||||
|
||||
@@ -20,14 +44,21 @@ int llcc68_init(const struct device *dev) {
|
||||
const struct llcc68_config *config = dev->config;
|
||||
struct llcc68_data *data = dev->data;
|
||||
|
||||
if (config->tx_enable_gpio.port != NULL) {
|
||||
if (config->rf_switch_mode == LLCC68_RF_SWITCH_GPIO_COMPLEMENTARY &&
|
||||
config->tx_enable_gpio.port != NULL) {
|
||||
gpio_pin_configure_dt(&config->tx_enable_gpio, GPIO_OUTPUT_INACTIVE);
|
||||
}
|
||||
|
||||
if (config->rx_enable_gpio.port != NULL) {
|
||||
if (config->rf_switch_mode == LLCC68_RF_SWITCH_GPIO_COMPLEMENTARY &&
|
||||
config->rx_enable_gpio.port != NULL) {
|
||||
gpio_pin_configure_dt(&config->rx_enable_gpio, GPIO_OUTPUT_INACTIVE);
|
||||
}
|
||||
|
||||
if (config->rf_switch_mode == LLCC68_RF_SWITCH_DIO2_SINGLE &&
|
||||
config->rx_enable_gpio.port != NULL) {
|
||||
gpio_pin_configure_dt(&config->rx_enable_gpio, GPIO_OUTPUT_ACTIVE);
|
||||
}
|
||||
|
||||
gpio_pin_configure_dt(&config->reset_gpio, GPIO_OUTPUT_INACTIVE);
|
||||
gpio_pin_configure_dt(&config->busy_gpio, GPIO_INPUT);
|
||||
gpio_pin_configure_dt(&config->dio1_gpio, GPIO_INPUT);
|
||||
@@ -42,24 +73,35 @@ int llcc68_init(const struct device *dev) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define LLCC68_DEFINE(inst) \
|
||||
static struct llcc68_data llcc68_data_##inst; \
|
||||
static const struct llcc68_config llcc68_config_##inst = \
|
||||
{ \
|
||||
.spi = SPI_DT_SPEC_INST_GET(inst, SPI_WORD_SET(8) | SPI_TRANSFER_MSB, 100), \
|
||||
.reset_gpio = GPIO_DT_SPEC_INST_GET(inst, reset_gpios), \
|
||||
.busy_gpio = GPIO_DT_SPEC_INST_GET(inst, busy_gpios), \
|
||||
.dio1_gpio = GPIO_DT_SPEC_INST_GET(inst, dio1_gpios), \
|
||||
.tx_enable_gpio = GPIO_DT_SPEC_INST_GET_OR(inst, tx_enable_gpios, {.port = NULL}), \
|
||||
.rx_enable_gpio = GPIO_DT_SPEC_INST_GET_OR(inst, rx_enable_gpios, {.port = NULL}), \
|
||||
}; \
|
||||
DEVICE_DT_INST_DEFINE(inst, \
|
||||
llcc68_init, \
|
||||
NULL, \
|
||||
&llcc68_data_##inst, \
|
||||
&llcc68_config_##inst, \
|
||||
POST_KERNEL, \
|
||||
CONFIG_LLCC68_INIT_PRIORITY, \
|
||||
#define LLCC68_DEFINE(inst) \
|
||||
BUILD_ASSERT(LLCC68_RF_SWITCH_MODE(inst) != LLCC68_RF_SWITCH_GPIO_COMPLEMENTARY || \
|
||||
(DT_INST_NODE_HAS_PROP(inst, tx_enable_gpios) && \
|
||||
DT_INST_NODE_HAS_PROP(inst, rx_enable_gpios)), \
|
||||
"LLCC68 gpio-complementary RF switch mode requires tx-enable-gpios " \
|
||||
"and rx-enable-gpios"); \
|
||||
BUILD_ASSERT(LLCC68_RF_SWITCH_MODE(inst) != LLCC68_RF_SWITCH_DIO2_SINGLE || \
|
||||
!DT_INST_NODE_HAS_PROP(inst, tx_enable_gpios), \
|
||||
"LLCC68 dio2-single RF switch mode uses DIO2 for TXEN and must not " \
|
||||
"define tx-enable-gpios"); \
|
||||
static struct llcc68_data llcc68_data_##inst; \
|
||||
static const struct llcc68_config llcc68_config_##inst = \
|
||||
{ \
|
||||
.spi = SPI_DT_SPEC_INST_GET( \
|
||||
inst, SPI_WORD_SET(8) | SPI_TRANSFER_MSB, LLCC68_SPI_CS_DELAY_US(inst)), \
|
||||
.reset_gpio = GPIO_DT_SPEC_INST_GET(inst, reset_gpios), \
|
||||
.busy_gpio = GPIO_DT_SPEC_INST_GET(inst, busy_gpios), \
|
||||
.dio1_gpio = GPIO_DT_SPEC_INST_GET(inst, dio1_gpios), \
|
||||
.tx_enable_gpio = GPIO_DT_SPEC_INST_GET_OR(inst, tx_enable_gpios, {.port = NULL}), \
|
||||
.rx_enable_gpio = GPIO_DT_SPEC_INST_GET_OR(inst, rx_enable_gpios, {.port = NULL}), \
|
||||
.rf_switch_mode = LLCC68_RF_SWITCH_MODE(inst), \
|
||||
}; \
|
||||
DEVICE_DT_INST_DEFINE(inst, \
|
||||
llcc68_init, \
|
||||
NULL, \
|
||||
&llcc68_data_##inst, \
|
||||
&llcc68_config_##inst, \
|
||||
POST_KERNEL, \
|
||||
CONFIG_LLCC68_INIT_PRIORITY, \
|
||||
NULL)
|
||||
|
||||
BUILD_ASSERT(DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT),
|
||||
|
||||
@@ -47,3 +47,33 @@ properties:
|
||||
description: |
|
||||
Antenna switch RX enable GPIO. If set, the driver tracks the
|
||||
state of the radio and controls the RF switch.
|
||||
|
||||
rf-switch-mode:
|
||||
type: string
|
||||
enum:
|
||||
- "none"
|
||||
- "gpio-complementary"
|
||||
- "dio2-single"
|
||||
description: |
|
||||
Optional RF switch control mode.
|
||||
|
||||
"none" disables RF switch handling.
|
||||
|
||||
"gpio-complementary" controls TXEN/RXEN from MCU GPIOs using the
|
||||
complementary table:
|
||||
idle: TXEN=0, RXEN=0
|
||||
RX: TXEN=0, RXEN=1
|
||||
TX: TXEN=1, RXEN=0
|
||||
This mode requires tx-enable-gpios and rx-enable-gpios.
|
||||
|
||||
"dio2-single" enables LLCC68 DIO2-as-RF-switch control for TXEN.
|
||||
RXEN must be externally pulled active or supplied as rx-enable-gpios,
|
||||
which the driver holds active. This mode must not use tx-enable-gpios.
|
||||
|
||||
spi-cs-setup-delay-ns:
|
||||
type: int
|
||||
default: 100000
|
||||
|
||||
spi-cs-hold-delay-ns:
|
||||
type: int
|
||||
default: 100000
|
||||
|
||||
+20
-3
@@ -11,7 +11,7 @@
|
||||
#include <zephyr/drivers/gpio.h>
|
||||
|
||||
namespace app::driver::llcc68 {
|
||||
constexpr size_t MAX_BUFFER_PAYLOAD = 128;
|
||||
constexpr size_t MAX_BUFFER_PAYLOAD = CONFIG_LLCC68_MAX_PAYLOAD_LENGTH;
|
||||
constexpr uint32_t TIMEOUT_NONE = 0;
|
||||
constexpr uint32_t TIMEOUT_INF = 0xffffffff;
|
||||
|
||||
@@ -41,12 +41,13 @@ constexpr auto DEFAULT_BUSY_TIMEOUT_MS = 100;
|
||||
* @param preamble_length Preamble length in symbols
|
||||
* @param header_type Header type (implicit or explicit).
|
||||
* @param crc_type CRC type (none or 16-bit)
|
||||
* @param ldro_on Low data rate optimization setting sent to the radio
|
||||
*/
|
||||
constexpr airtime_t calc_time_on_air(uint8_t len, uint8_t sf, LoRaBandwidth bw,
|
||||
LoRaCodingRate cr,
|
||||
uint16_t preamble_length,
|
||||
LoRaHeaderType header_type,
|
||||
LoRaCrcType crc_type);
|
||||
LoRaCrcType crc_type, bool ldro_on);
|
||||
|
||||
struct LLCC68 {
|
||||
/** trivial getter */
|
||||
@@ -119,7 +120,7 @@ struct LLCC68 {
|
||||
uint8_t offset, std::span<const uint8_t> data_from_host,
|
||||
timeout_ms_t busy_timeout = DEFAULT_BUSY_TIMEOUT_MS);
|
||||
|
||||
void tx_rx_en_pin_set(TxRxPinState state);
|
||||
expected<unit, error_code> set_rf_switch_state(RfSwitchState state);
|
||||
|
||||
/** LLCC68 DataSheet Function */
|
||||
|
||||
@@ -238,6 +239,21 @@ struct LLCC68 {
|
||||
|
||||
expected<unit, error_code> set_tx(uint32_t timeout = TIMEOUT_NONE);
|
||||
expected<unit, error_code> set_rx(uint32_t timeout = TIMEOUT_INF);
|
||||
/**
|
||||
* @brief Start LLCC68 RX duty-cycle/listen mode.
|
||||
*
|
||||
* rx_period and sleep_period are raw 24-bit LLCC68 RTC periods, not
|
||||
* milliseconds. Datasheet section 13.1.7 defines one period as 15.625 us:
|
||||
* RX duration = rx_period * 15.625 us
|
||||
* sleep duration = sleep_period * 15.625 us
|
||||
*
|
||||
* Use rx_duty_cycle_period_from_ms() or set_rx_duty_cycle_ms() when caller
|
||||
* inputs are in milliseconds.
|
||||
*/
|
||||
expected<unit, error_code> set_rx_duty_cycle(uint32_t rx_period,
|
||||
uint32_t sleep_period);
|
||||
expected<unit, error_code> set_rx_duty_cycle_ms(uint32_t rx_period_ms,
|
||||
uint32_t sleep_period_ms);
|
||||
expected<unit, error_code> set_sleep(sleep_config_t config);
|
||||
expected<unit, error_code> set_tx_continuous_wave();
|
||||
expected<unit, error_code> set_tx_infinite_preamble();
|
||||
@@ -287,6 +303,7 @@ struct LLCC68 {
|
||||
|
||||
/** properties */
|
||||
const struct device *dev;
|
||||
std::optional<ChipType> cached_chip_type{};
|
||||
};
|
||||
} // namespace app::driver::llcc68
|
||||
|
||||
|
||||
+848
-761
File diff suppressed because it is too large
Load Diff
@@ -6,7 +6,7 @@
|
||||
#include <zephyr/types.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#define LLCC68_MAX_BUFFER_PAYLOAD 128
|
||||
#define LLCC68_MAX_BUFFER_PAYLOAD CONFIG_LLCC68_MAX_PAYLOAD_LENGTH
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@@ -14,6 +14,12 @@ extern "C" {
|
||||
|
||||
typedef void (*llcc68_user_dio1_handler_t)(const struct device *dev, void *user_data);
|
||||
|
||||
enum llcc68_rf_switch_mode {
|
||||
LLCC68_RF_SWITCH_NONE = 0,
|
||||
LLCC68_RF_SWITCH_GPIO_COMPLEMENTARY = 1,
|
||||
LLCC68_RF_SWITCH_DIO2_SINGLE = 2,
|
||||
};
|
||||
|
||||
struct llcc68_config {
|
||||
struct spi_dt_spec spi;
|
||||
struct gpio_dt_spec reset_gpio;
|
||||
@@ -21,6 +27,7 @@ struct llcc68_config {
|
||||
struct gpio_dt_spec dio1_gpio;
|
||||
struct gpio_dt_spec tx_enable_gpio;
|
||||
struct gpio_dt_spec rx_enable_gpio;
|
||||
enum llcc68_rf_switch_mode rf_switch_mode;
|
||||
};
|
||||
|
||||
struct llcc68_data {
|
||||
|
||||
+1331
-1124
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user