diff --git a/docs/DS_LLCC68 V1-1.pdf b/docs/DS_LLCC68 V1-1.pdf new file mode 100644 index 0000000..f7a82e0 --- /dev/null +++ b/docs/DS_LLCC68 V1-1.pdf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:cd571cdecccdbd8740995c68849a7c38241fe95cdf24a07e63edead537f245e4 +size 4304842 diff --git a/docs/DS_LLCC68_V1.0.pdf b/docs/DS_LLCC68_V1.0.pdf deleted file mode 100644 index 1d24c41..0000000 --- a/docs/DS_LLCC68_V1.0.pdf +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:cd5ad5e647b0e0e58e3bd90fdb663173ef0974dfbd478dd8a79d4101f4f46e17 -size 2194155 diff --git a/inc/llcc68.hpp b/inc/llcc68.hpp index 9e3df7b..e5fbf86 100644 --- a/inc/llcc68.hpp +++ b/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 using Result = app::utils::Result; using Unit = app::utils::Unit; -using millisecond = std::chrono::duration; +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,41 +308,41 @@ 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 -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}) { - 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}) { - 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}) { - 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}) { - data[0] = RADIOLIB_SX126X_CAL_IMG_470_MHZ_1; - data[1] = RADIOLIB_SX126X_CAL_IMG_470_MHZ_2; - } else { - data[0] = RADIOLIB_SX126X_CAL_IMG_430_MHZ_1; - data[1] = RADIOLIB_SX126X_CAL_IMG_430_MHZ_2; - } - auto res = spi::write_stream(RADIOLIB_SX126X_CMD_CALIBRATE_IMAGE, data); - APP_RADIO_RETURN_ERR(res); - delay_ms(5); + uint8_t data[2]; + 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 > 850.0) { + data[0] = RADIOLIB_SX126X_CAL_IMG_863_MHZ_1; + data[1] = RADIOLIB_SX126X_CAL_IMG_863_MHZ_2; + } 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 > 460.0) { + data[0] = RADIOLIB_SX126X_CAL_IMG_470_MHZ_1; + data[1] = RADIOLIB_SX126X_CAL_IMG_470_MHZ_2; + } else { + data[0] = RADIOLIB_SX126X_CAL_IMG_430_MHZ_1; + data[1] = RADIOLIB_SX126X_CAL_IMG_430_MHZ_2; } - - return set_rf_frequency(frequency_raw(freq)); + auto res = spi::write_stream(RADIOLIB_SX126X_CMD_CALIBRATE_IMAGE, data); + APP_RADIO_RETURN_ERR(res); + delay_ms(5); + return {}; } inline Result @@ -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 -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 config_packet_type(uint8_t sf) { +inline Result +set_packet_type_lora(uint8_t sf) { Result 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{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{data, 1}); APP_RADIO_RETURN_ERR(res); @@ -500,15 +505,27 @@ inline Result config_packet_type(uint8_t sf) { res = spi::write_stream(RADIOLIB_SX126X_CMD_SET_CAD_PARAMS, std::span{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{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 +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 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,13 +541,12 @@ inline Result 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, - uint8_t sf, - uint8_t bw, - uint8_t cr, - uint16_t preamble_length, - uint8_t header_type) { +constexpr uint32_t calc_time_on_air(const size_t len, + uint8_t sf, + uint8_t bw, + uint8_t cr, + uint16_t preamble_length, + uint8_t header_type) { // everything is in microseconds to allow integer arithmetic // some constants have .25, these are multiplied by 4, and have _x4 postfix to indicate that fact const auto bw_ = float{bw_khz(bw)}; @@ -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 -bool static_is_use_ldr() { - constexpr auto khz = bw_khz(bw); - constexpr auto symbol_length = static_cast(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 Result Result