feat: update LLCC68 documentation and replace outdated PDF with the latest version
This commit is contained in:
BIN
docs/DS_LLCC68 V1-1.pdf
LFS
Normal file
BIN
docs/DS_LLCC68 V1-1.pdf
LFS
Normal file
Binary file not shown.
BIN
docs/DS_LLCC68_V1.0.pdf
LFS
BIN
docs/DS_LLCC68_V1.0.pdf
LFS
Binary file not shown.
127
inc/llcc68.hpp
127
inc/llcc68.hpp
@ -65,6 +65,7 @@ constexpr auto MAX_RX_BUFFER_SIZE = 0xff - DEFAULT_RX_BUFFER_ADDRESS;
|
||||
|
||||
/**
|
||||
* @brief return if STATEVAR has value that is NOT RADIO_TRANS_CMD_PROC_ERR
|
||||
* @note some read operation would still succeed even if the command processing error occurs
|
||||
*/
|
||||
#define APP_RADIO_RETURN_ERR_IGNORE_PROC_ERR(STATEVAR) \
|
||||
{ \
|
||||
@ -100,12 +101,13 @@ template <typename T, typename E>
|
||||
using Result = app::utils::Result<T, E>;
|
||||
using Unit = app::utils::Unit;
|
||||
|
||||
using millisecond = std::chrono::duration<size_t, std::milli>;
|
||||
using millisecond = app::utils::Instant::milliseconds;
|
||||
|
||||
/**
|
||||
* \brief Whether to use only LDO regulator (true) or DC-DC regulator (false)
|
||||
*/
|
||||
constexpr bool USE_REGULATOR_LDO = true;
|
||||
|
||||
/*!
|
||||
\brief Whether the module has an XTAL (true) or TCXO (false)
|
||||
|
||||
@ -306,29 +308,31 @@ inline constexpr uint32_t frequency_raw(const freq_t freq) {
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Set the RF frequency in MHz, with necessary calibration and checks
|
||||
* \param freq the frequency to set, which must be in range [150, 960]
|
||||
* \param calibrate whether to calibrate the image
|
||||
* \sa set_frequency_raw
|
||||
* @brief Image calibration is done through the command CalibrateImage(...) for
|
||||
* a given range of frequencies defined by the parameters freq1
|
||||
* and freq2. Once performed, the calibration is valid for all frequencies between
|
||||
* the two extremes used as parameters. Typically, the user can select the
|
||||
* parameters freq1 and freq2 to cover any specific ISM band.
|
||||
*
|
||||
* @param freq the expected frequency in MHz
|
||||
* @sa 9.2.1 Image Calibration for Specific Frequency Bands
|
||||
*/
|
||||
inline Result<Unit, error_t>
|
||||
set_frequency(freq_t freq, const bool calibrate = true) {
|
||||
using f_t = decltype(freq);
|
||||
calibrate_image(freq_t freq) {
|
||||
if (not valid_freq(freq)) {
|
||||
return ue_t{error_t{error::RADIO_INVALID_FREQUENCY}};
|
||||
}
|
||||
if (calibrate) {
|
||||
uint8_t data[2];
|
||||
if (freq > f_t{900}) {
|
||||
if (freq > 900.0) {
|
||||
data[0] = RADIOLIB_SX126X_CAL_IMG_902_MHZ_1;
|
||||
data[1] = RADIOLIB_SX126X_CAL_IMG_902_MHZ_2;
|
||||
} else if (freq > f_t{850.0}) {
|
||||
} else if (freq > 850.0) {
|
||||
data[0] = RADIOLIB_SX126X_CAL_IMG_863_MHZ_1;
|
||||
data[1] = RADIOLIB_SX126X_CAL_IMG_863_MHZ_2;
|
||||
} else if (freq > f_t{770.0}) {
|
||||
} else if (freq > 770.0) {
|
||||
data[0] = RADIOLIB_SX126X_CAL_IMG_779_MHZ_1;
|
||||
data[1] = RADIOLIB_SX126X_CAL_IMG_779_MHZ_2;
|
||||
} else if (freq > f_t{460.0}) {
|
||||
} else if (freq > 460.0) {
|
||||
data[0] = RADIOLIB_SX126X_CAL_IMG_470_MHZ_1;
|
||||
data[1] = RADIOLIB_SX126X_CAL_IMG_470_MHZ_2;
|
||||
} else {
|
||||
@ -338,9 +342,7 @@ set_frequency(freq_t freq, const bool calibrate = true) {
|
||||
auto res = spi::write_stream(RADIOLIB_SX126X_CMD_CALIBRATE_IMAGE, data);
|
||||
APP_RADIO_RETURN_ERR(res);
|
||||
delay_ms(5);
|
||||
}
|
||||
|
||||
return set_rf_frequency(frequency_raw(freq));
|
||||
return {};
|
||||
}
|
||||
|
||||
inline Result<uint8_t, error_t>
|
||||
@ -455,7 +457,7 @@ struct irq_params_t {
|
||||
* By default, all IRQ are masked (all ‘0’) and the user can enable them one by one (or several at a time) by setting the corresponding mask to ‘1’.
|
||||
*/
|
||||
inline Result<Unit, error_t>
|
||||
set_dio_irq_params(const irq_params_t &irq_params) {
|
||||
set_dio_irq_params(irq_params_t irq_params) {
|
||||
const auto irqMask = irq_params.irqMask;
|
||||
const auto dio1Mask = irq_params.dio1Mask;
|
||||
const auto dio2Mask = irq_params.dio2Mask;
|
||||
@ -477,15 +479,18 @@ set_dio2_as_rf_switch(const bool en) {
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief set packet type and do the calibration
|
||||
* \sa SetPacketType
|
||||
*/
|
||||
inline Result<Unit, error_t> config_packet_type(uint8_t sf) {
|
||||
inline Result<Unit, error_t>
|
||||
set_packet_type_lora(uint8_t sf) {
|
||||
Result<Unit, error_t> res;
|
||||
constexpr auto mod = RADIOLIB_SX126X_PACKET_TYPE_LORA;
|
||||
uint8_t data[7];
|
||||
data[0] = mod;
|
||||
res = spi::write_stream(RADIOLIB_SX126X_CMD_SET_PACKET_TYPE, std::span<const uint8_t>{data, 1});
|
||||
APP_RADIO_RETURN_ERR(res);
|
||||
// the command SetRxTxFallbackMode() defines into which mode the chip goes
|
||||
// after a successful transmission or after a packet reception.
|
||||
data[0] = RADIOLIB_SX126X_RX_TX_FALLBACK_MODE_STDBY_RC;
|
||||
res = spi::write_stream(RADIOLIB_SX126X_CMD_SET_RX_TX_FALLBACK_MODE, std::span<const uint8_t>{data, 1});
|
||||
APP_RADIO_RETURN_ERR(res);
|
||||
@ -500,15 +505,27 @@ inline Result<Unit, error_t> config_packet_type(uint8_t sf) {
|
||||
res = spi::write_stream(RADIOLIB_SX126X_CMD_SET_CAD_PARAMS, std::span<const uint8_t>{data, 7});
|
||||
APP_RADIO_RETURN_ERR(res);
|
||||
|
||||
clear_irq_status();
|
||||
// default init to be non-interrupt
|
||||
std::ignore = clear_irq_status();
|
||||
constexpr auto irq_params = irq_params_t{};
|
||||
res = set_dio_irq_params(irq_params);
|
||||
APP_RADIO_RETURN_ERR(res);
|
||||
while (gpio::digital_read(BUSY_PIN) == gpio::HIGH) {}
|
||||
return {};
|
||||
}
|
||||
|
||||
#ifndef APP_RADIO_DISABLE_CALIBRATION
|
||||
data[0] = RADIOLIB_SX126X_CALIBRATE_ALL;
|
||||
res = spi::write_stream(RADIOLIB_SX126X_CMD_CALIBRATE, std::span<const uint8_t>{data, 1});
|
||||
|
||||
/**
|
||||
* \brief At power up the radio performs calibration of RC64k, RC13M, PLL and
|
||||
* ADC. It is however possible to launch a calibration of one or several
|
||||
* blocks at any time starting in STDBY_RC mode. The calibrate function starts the
|
||||
* calibration of a block defined by calibParam.
|
||||
* \sa 13.1.12 Calibrate Function
|
||||
*/
|
||||
inline Result<Unit, error_t>
|
||||
calibrate(uint8_t calibParam = RADIOLIB_SX126X_CALIBRATE_ALL) {
|
||||
uint8_t data[1];
|
||||
data[0] = calibParam;
|
||||
auto res = spi::write_stream(RADIOLIB_SX126X_CMD_CALIBRATE, data);
|
||||
APP_RADIO_RETURN_ERR(res);
|
||||
// The total calibration time if all blocks are calibrated is 3.5 ms. The
|
||||
// calibration must be launched in STDBY_RC mode and the BUSY pins will be
|
||||
@ -516,7 +533,6 @@ inline Result<Unit, error_t> config_packet_type(uint8_t sf) {
|
||||
// end of the procedure.
|
||||
delay_ms(5);
|
||||
while (gpio::digital_read(BUSY_PIN) == gpio::HIGH) {}
|
||||
#endif /** APP_RADIO_DISABLE_CALIBRATION */
|
||||
return {};
|
||||
}
|
||||
|
||||
@ -525,8 +541,7 @@ inline Result<Unit, error_t> config_packet_type(uint8_t sf) {
|
||||
\param len Payload length in bytes.
|
||||
\returns Expected time-on-air in microseconds.
|
||||
*/
|
||||
constexpr uint32_t
|
||||
calc_time_on_air(const size_t len,
|
||||
constexpr uint32_t calc_time_on_air(const size_t len,
|
||||
uint8_t sf,
|
||||
uint8_t bw,
|
||||
uint8_t cr,
|
||||
@ -840,16 +855,6 @@ set_TCXO(const TcxoVoltage voltage, const uint32_t delay = 5000, const bool XTAL
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* \brief if the symbol (length := 2^sf / bw_khz) > 16, then we're using LDR
|
||||
*/
|
||||
template <uint8_t bw, uint32_t sf>
|
||||
bool static_is_use_ldr() {
|
||||
constexpr auto khz = bw_khz(bw);
|
||||
constexpr auto symbol_length = static_cast<uint32_t>(std::pow(2, sf) / khz);
|
||||
return symbol_length > 16;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief set LoRa modulation parameters
|
||||
* \param sf spread factor (5-12)
|
||||
@ -1296,32 +1301,6 @@ static constexpr auto begin = [](const lora_parameters_t ¶ms) -> Result<Unit
|
||||
return ue_t{error_t{error::RADIO_CHIP_NOT_FOUND}};
|
||||
}
|
||||
|
||||
/**
|
||||
* FIXME
|
||||
*
|
||||
* The hardware of the SX126x chips can be designed to use either an
|
||||
* internal LDO or an internal DCDC converter. The DCDC converter provides
|
||||
* better current savings and will be used in most modules. If there are
|
||||
* problems to get the SX126x to work, check which HW configuration is used
|
||||
* and set USE_LDO accordingly.
|
||||
* If USE_LDO is not set in the hwConfig, DCDC is used as default.
|
||||
*
|
||||
* - RADIO_TXEN and RADIO_RXEN are used on eByte E22-900M22S module to
|
||||
* switch the antenna between RX and TX
|
||||
* - DIO2 as antenna switch is used in the example Semtech design as default
|
||||
* and might be used by many modules
|
||||
* - DIO3 as antenna switch is used by e.g. Insight SIP ISP4520 module which
|
||||
* integrates a nRF52832 and a SX126x chip
|
||||
* - Some modules use DIO3 to control the power supply of the TXCO.
|
||||
* - Some modules use DIO2 to switch the antenna between RX and TX and a
|
||||
* separate GPIO to power the antenna switch on or off. Switching the
|
||||
* antenna switch off can reduce the power consumption. The GPIO used to
|
||||
* control the antenna power is defined as RADIO_RXEN. LOW == power off,
|
||||
* HIGH == power on.
|
||||
*
|
||||
* @sa https://github.com/beegee-tokyo/SX126x-Arduino?tab=readme-ov-file#explanation-for-ldo-and-dcdc-selection
|
||||
*/
|
||||
|
||||
if constexpr (USE_TXCO) {
|
||||
const auto res = set_TCXO(DEFAULT_TCXO_VOLTAGE);
|
||||
APP_RADIO_RETURN_ERR_CTX(res, "set TCXO");
|
||||
@ -1329,10 +1308,14 @@ static constexpr auto begin = [](const lora_parameters_t ¶ms) -> Result<Unit
|
||||
const auto &mod_params = params.mod_params;
|
||||
const auto &packet_params = params.packet_params;
|
||||
|
||||
// SetPacketType
|
||||
res = config_packet_type(mod_params.sf);
|
||||
res = set_packet_type_lora(mod_params.sf);
|
||||
APP_RADIO_RETURN_ERR_CTX(res, "config packet type");
|
||||
|
||||
#ifndef APP_RADIO_DISABLE_CALIBRATION
|
||||
res = calibrate();
|
||||
APP_RADIO_RETURN_ERR_CTX(res, "calibrate");
|
||||
#endif /* APP_RADIO_DISABLE_CALIBRATION */
|
||||
|
||||
res = set_modulation_params(mod_params.sf,
|
||||
mod_params.bw,
|
||||
mod_params.cr,
|
||||
@ -1352,17 +1335,15 @@ static constexpr auto begin = [](const lora_parameters_t ¶ms) -> Result<Unit
|
||||
res = set_dio2_as_rf_switch(false);
|
||||
APP_RADIO_RETURN_ERR_CTX(res, "set dio2 as rf switch");
|
||||
|
||||
#ifdef APP_RADIO_DISABLE_CALIBRATION
|
||||
res = set_frequency(params.frequency, false);
|
||||
res = get_device_error_print_and_clear(TAG);
|
||||
#else
|
||||
res = set_frequency(params.frequency, true);
|
||||
res = get_device_error_print_and_clear(TAG);
|
||||
#endif /* APP_RADIO_DISABLE_CALIBRATION */
|
||||
|
||||
res = set_rf_frequency(params.frequency);
|
||||
APP_RADIO_RETURN_ERR_CTX(res, "set frequency");
|
||||
|
||||
// SetPacketParams
|
||||
#ifndef APP_RADIO_DISABLE_CALIBRATION
|
||||
res = calibrate_image(params.frequency);
|
||||
res = get_device_error_print_and_clear(TAG);
|
||||
APP_RADIO_RETURN_ERR_CTX(res, "calibrate image");
|
||||
#endif /* APP_RADIO_DISABLE_CALIBRATION */
|
||||
|
||||
res = set_packet_params(packet_params.preamble_len,
|
||||
packet_params.payload_len,
|
||||
packet_params.crc_type,
|
||||
|
||||
Reference in New Issue
Block a user