From 85f816850ba04862b47556169730d954431a0273 Mon Sep 17 00:00:00 2001 From: Alex Mikhalev Date: Sat, 29 Dec 2018 22:07:22 -0700 Subject: [PATCH] Refactor sx127x_driver into a component --- components/sx127x_driver/CMakeLists.txt | 8 + components/sx127x_driver/sx127x_driver.c | 175 +++++++ .../sx127x_driver/sx127x_driver.h | 12 - components/sx127x_driver/sx127x_internal.h | 112 +++++ components/sx127x_driver/sx127x_registers.c | 184 +++++++ components/sx127x_driver/sx127x_registers.h | 20 + main/CMakeLists.txt | 8 +- main/sx127x_driver/sx127x_driver.c | 468 ------------------ 8 files changed, 502 insertions(+), 485 deletions(-) create mode 100644 components/sx127x_driver/CMakeLists.txt create mode 100644 components/sx127x_driver/sx127x_driver.c rename {main => components}/sx127x_driver/sx127x_driver.h (82%) create mode 100644 components/sx127x_driver/sx127x_internal.h create mode 100644 components/sx127x_driver/sx127x_registers.c create mode 100644 components/sx127x_driver/sx127x_registers.h delete mode 100644 main/sx127x_driver/sx127x_driver.c diff --git a/components/sx127x_driver/CMakeLists.txt b/components/sx127x_driver/CMakeLists.txt new file mode 100644 index 0000000..0b90858 --- /dev/null +++ b/components/sx127x_driver/CMakeLists.txt @@ -0,0 +1,8 @@ +set(COMPONENT_SRCS + "sx127x_driver.c" + "sx127x_registers.c") +set(COMPONENT_ADD_INCLUDEDIRS ".") + +register_component() + +component_compile_options("-Werror=incompatible-pointer-types") diff --git a/components/sx127x_driver/sx127x_driver.c b/components/sx127x_driver/sx127x_driver.c new file mode 100644 index 0000000..258712b --- /dev/null +++ b/components/sx127x_driver/sx127x_driver.c @@ -0,0 +1,175 @@ +#include "sx127x_driver.h" +#include "sx127x_internal.h" +#include "sx127x_registers.h" + +#include +#include + +const char *SX127X_TAG = "sx127x"; + +esp_err_t sx127x_init(sx127x_config_t *config, sx127x_t **handle_ptr) { + esp_err_t ret; + sx127x_t *handle = malloc(sizeof(sx127x_t)); + SX127X_CHECK(handle != NULL, "malloc error", ESP_ERR_NO_MEM); + + handle->task_handle = NULL; + memcpy(&handle->config, config, sizeof(sx127x_config_t)); + + ret = gpio_set_direction(config->rst_io_num, GPIO_MODE_OUTPUT); + SX127X_ERROR_CHECK2(ret, gpio_set_direction) + + // perform reset + gpio_set_level(config->rst_io_num, 0); + vTaskDelay(RESET_DELAY); + gpio_set_level(config->rst_io_num, 1); + vTaskDelay(RESET_DELAY); + + spi_bus_config_t bus_config = {.mosi_io_num = config->mosi_io_num, + .miso_io_num = config->miso_io_num, + .sclk_io_num = config->sck_io_num, + .quadhd_io_num = -1, + .quadwp_io_num = -1, + .max_transfer_sz = SX127X_MAX_TRANSFER}; + ret = spi_bus_initialize(config->spi_host, &bus_config, 1); + SX127X_ERROR_CHECK2(ret, spi_bus_initialize) + + spi_device_interface_config_t device_config = { + .command_bits = 0, + .address_bits = 8, + .dummy_bits = 0, + .mode = 0, + .duty_cycle_pos = 0, + .cs_ena_pretrans = 0, + .cs_ena_posttrans = 0, + .clock_speed_hz = SPI_CLOCK_HZ, // 8mhz + .input_delay_ns = 0, + .spics_io_num = config->cs_io_num, + .flags = 0, + .queue_size = 8, + .pre_cb = NULL, + .post_cb = NULL, + }; + ret = spi_bus_add_device(config->spi_host, &device_config, &handle->device_handle); + SX127X_ERROR_CHECK2(ret, spi_bus_add_device) + + // read version and check that it is compatible + uint8_t version; + ret = sx127x_read_register(handle, REG_VERSION, &version); + SX127X_ERROR_CHECK2(ret, sx127x_read_register); + SX127X_CHECK(version == 0x12, "unsupported version %#x", ESP_ERR_INVALID_VERSION, version); + + ret = sx127x_sleep(handle); + SX127X_ERROR_CHECK(ret); + + ret = sx127x_set_frequency(handle, config->frequency); + SX127X_ERROR_CHECK(ret); + + ret = sx127x_write_register(handle, REG_FIFO_TX_BASE_ADDR, 0); + SX127X_ERROR_CHECK(ret); + sx127x_write_register(handle, REG_FIFO_RX_BASE_ADDR, 0); + SX127X_ERROR_CHECK(ret); + + uint8_t reg_lna; + ret = sx127x_read_register(handle, REG_LNA, ®_lna); + SX127X_ERROR_CHECK(ret); + reg_lna |= 0x03; // set LNA boost + ret = sx127x_write_register(handle, REG_LNA, reg_lna); + SX127X_ERROR_CHECK(ret); + + // set auto AGC + ret = sx127x_write_register(handle, REG_MODEM_CONFIG_3, CONFIG3_AUTO_AGC); + SX127X_ERROR_CHECK(ret); + + ret = sx127x_set_tx_power(handle, config->tx_power, true); + SX127X_ERROR_CHECK(ret); + + ret = sx127x_set_spreading_factor(handle, config->spreading_factor); + SX127X_ERROR_CHECK(ret); + + ret = sx127x_set_sync_word(handle, config->sync_word); + SX127X_ERROR_CHECK(ret); + + ret = sx127x_set_crc(handle, config->crc); + SX127X_ERROR_CHECK(ret); + + ret = sx127x_standby(handle); + ESP_ERROR_CHECK(ret); + + *handle_ptr = handle; + return ESP_OK; +} + +esp_err_t sx127x_free(sx127x_t *handle) { + esp_err_t ret; + + if (handle->task_handle) { + ret = sx127x_stop(handle); + SX127X_ERROR_CHECK(ret); + } + + ret = spi_bus_remove_device(handle->device_handle); + SX127X_ERROR_CHECK2(ret, spi_bus_remove_device) + + ret = spi_bus_free(handle->config.spi_host); + SX127X_ERROR_CHECK2(ret, spi_bus_free) + + free(handle); + + return ESP_OK; +} + +void sx127x_isr(void *arg) { + sx127x_t *handle = (sx127x_t *)arg; + ESP_LOGI(SX127X_TAG, "sx127x_isr"); +} + +void sx127x_task(void *arg) { + sx127x_t *handle = (sx127x_t *)arg; + while (handle->task_running) { + vTaskDelay(pdMS_TO_TICKS(10)); + } +} + +esp_err_t sx127x_start(sx127x_t *handle) { + esp_err_t ret; + + SX127X_CHECK(handle->task_handle == NULL, "task already running", ESP_ERR_INVALID_STATE); + + ret = sx127x_write_register(handle, REG_DIO_MAPPING_1, 0x00); + SX127X_ERROR_CHECK(ret); + + gpio_config_t irq_io_config; + irq_io_config.intr_type = GPIO_INTR_POSEDGE; + irq_io_config.mode = GPIO_MODE_INPUT; + irq_io_config.pin_bit_mask = (1ULL << handle->config.irq_io_num); + irq_io_config.pull_down_en = 0; + irq_io_config.pull_up_en = 0; + ret = gpio_config(&irq_io_config); + SX127X_ERROR_CHECK2(ret, gpio_config) + + ret = gpio_install_isr_service(ESP_INTR_FLAG_LEVEL1); + SX127X_ERROR_CHECK2(ret, gpio_install_isr_service); + ret = gpio_isr_handler_add(handle->config.irq_io_num, sx127x_isr, (void *)handle); + SX127X_ERROR_CHECK2(ret, gpio_isr_handler_add); + + handle->task_running = true; + + BaseType_t pdRet = + xTaskCreate(sx127x_task, "sx127x_task", TASK_STACK_SIZE, (void *)handle, TASK_PRIORITY, &handle->task_handle); + SX127X_CHECK(pdRet == pdPASS, "failed to create task", ESP_FAIL); + return ESP_OK; +} + +esp_err_t sx127x_stop(sx127x_t *handle) { + esp_err_t ret; + + SX127X_CHECK(handle->task_handle != NULL, "task has not been started", ESP_ERR_INVALID_STATE); + handle->task_running = false; + xTaskNotify(handle->task_handle, 0, eNoAction); + + ret = gpio_isr_handler_remove(handle->config.irq_io_num); + SX127X_ERROR_CHECK2(ret, gpio_isr_handler_remove); + gpio_uninstall_isr_service(); + + return ESP_OK; +} diff --git a/main/sx127x_driver/sx127x_driver.h b/components/sx127x_driver/sx127x_driver.h similarity index 82% rename from main/sx127x_driver/sx127x_driver.h rename to components/sx127x_driver/sx127x_driver.h index 78cf36f..f9fbc0b 100644 --- a/main/sx127x_driver/sx127x_driver.h +++ b/components/sx127x_driver/sx127x_driver.h @@ -76,18 +76,6 @@ esp_err_t sx127x_init(sx127x_config_t *config, sx127x_t **handle_ptr); esp_err_t sx127x_free(sx127x_t *handle); -esp_err_t sx127x_set_frequency(sx127x_t *handle, uint64_t frequency); - -esp_err_t sx127x_set_tx_power(sx127x_t *handle, uint8_t tx_power, sx127x_pa_boost_t pa_boost); - -esp_err_t sx127x_set_spreading_factor(sx127x_t *handle, uint8_t spreading_factor); - -esp_err_t sx127x_set_signal_bandwidth(sx127x_t *handle, uint64_t signal_bandwidth); - -esp_err_t sx127x_set_sync_word(sx127x_t *handle, uint8_t sync_word); - -esp_err_t sx127x_set_crc(sx127x_t *handle, sx127x_crc_t crc); - esp_err_t sx127x_sleep(sx127x_t *handle); esp_err_t sx127x_standby(sx127x_t *handle); diff --git a/components/sx127x_driver/sx127x_internal.h b/components/sx127x_driver/sx127x_internal.h new file mode 100644 index 0000000..853c18d --- /dev/null +++ b/components/sx127x_driver/sx127x_internal.h @@ -0,0 +1,112 @@ +#include +#include + +#define MAX_PKT_LENGTH 255 +#define RESET_DELAY (pdMS_TO_TICKS(15)) +// 8mhz +#define SPI_CLOCK_HZ (8 * 1000 * 1000) +#define TASK_STACK_SIZE (2 * 1024) +#define TASK_PRIORITY 3 + +#define REG_FIFO 0x00 +#define REG_OP_MODE 0x01 +#define REG_FRF_MSB 0x06 +#define REG_FRF_MID 0x07 +#define REG_FRF_LSB 0x08 +#define REG_PA_CONFIG 0x09 +#define REG_OCP 0x0b +#define REG_LNA 0x0c +#define REG_FIFO_ADDR_PTR 0x0d +#define REG_FIFO_TX_BASE_ADDR 0x0e +#define REG_FIFO_RX_BASE_ADDR 0x0f +#define REG_FIFO_RX_CURRENT_ADDR 0x10 +#define REG_IRQ_FLAGS 0x12 +#define REG_RX_NB_BYTES 0x13 +#define REG_PKT_SNR_VALUE 0x19 +#define REG_PKT_RSSI_VALUE 0x1a +#define REG_MODEM_CONFIG_1 0x1d +#define REG_MODEM_CONFIG_2 0x1e +#define REG_PREAMBLE_MSB 0x20 +#define REG_PREAMBLE_LSB 0x21 +#define REG_PAYLOAD_LENGTH 0x22 +#define REG_MODEM_CONFIG_3 0x26 +#define REG_FREQ_ERROR_MSB 0x28 +#define REG_FREQ_ERROR_MID 0x29 +#define REG_FREQ_ERROR_LSB 0x2a +#define REG_RSSI_WIDEBAND 0x2c +#define REG_DETECTION_OPTIMIZE 0x31 +#define REG_INVERTIQ 0x33 +#define REG_DETECTION_THRESHOLD 0x37 +#define REG_SYNC_WORD 0x39 +#define REG_INVERTIQ2 0x3b +#define REG_DIO_MAPPING_1 0x40 +#define REG_VERSION 0x42 +#define REG_PA_DAC 0x4d + +// modes +#define MODE_LONG_RANGE_MODE 0x80 +#define MODE_SLEEP 0x00 +#define MODE_STDBY 0x01 +#define MODE_TX 0x03 +#define MODE_RX_CONTINUOUS 0x05 +#define MODE_RX_SINGLE 0x06 + +#define CONFIG2_CRC 0x04 +#define CONFIG3_AUTO_AGC 0x04 + +// PA config +#define PA_BOOST 0x80 + +// IRQ masks +#define IRQ_TX_DONE_MASK 0x08 +#define IRQ_PAYLOAD_CRC_ERROR_MASK 0x20 +#define IRQ_RX_DONE_MASK 0x40 + +#ifdef NODEBUG +#define SX127X_CHECK(check, str, ret_val, ...) \ + if (!(check)) { \ + ESP_LOGE(SX127X_TAG, "%s(%d): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__); \ + return (ret_val); \ + } +#define SX127X_ERROR_CHECK(ret) \ + { \ + esp_err_t _error_code = (ret); \ + if (_error_code != ESP_OK) { \ + return _error_code; \ + } \ + } +#define SX127X_ERROR_CHECK2(ret, fun) SX127X_CHECK(ret) +#else +#define SX127X_CHECK(check, str, ret_val, ...) \ + if (!(check)) { \ + ESP_LOGE(SX127X_TAG, "%s(%d): " #check ": " str, __FUNCTION__, __LINE__, ##__VA_ARGS__); \ + return (ret_val); \ + } +#define SX127X_ERROR_CHECK(ret) \ + { \ + esp_err_t _error_code = (ret); \ + if (_error_code != ESP_OK) { \ + const char *_error_name = esp_err_to_name(_error_code); \ + ESP_LOGE(SX127X_TAG, "%s(%d): %s (%d)", __FUNCTION__, __LINE__, _error_name, _error_code); \ + return _error_code; \ + } \ + } +#define SX127X_ERROR_CHECK2(ret, fun) \ + { \ + esp_err_t _error_code = (ret); \ + if (_error_code != ESP_OK) { \ + const char *_error_name = esp_err_to_name(_error_code); \ + ESP_LOGE(SX127X_TAG, "%s(%d): " #fun ": %s (%d)", __FUNCTION__, __LINE__, _error_name, _error_code); \ + return _error_code; \ + } \ + } +#endif + +struct sx127x { + sx127x_config_t config; + spi_device_handle_t device_handle; + TaskHandle_t task_handle; + bool task_running; +}; + +const char *SX127X_TAG; diff --git a/components/sx127x_driver/sx127x_registers.c b/components/sx127x_driver/sx127x_registers.c new file mode 100644 index 0000000..04813ef --- /dev/null +++ b/components/sx127x_driver/sx127x_registers.c @@ -0,0 +1,184 @@ +#include "sx127x_registers.h" +#include "sx127x_internal.h" + +#include + +esp_err_t sx127x_read_register(sx127x_t *handle, uint8_t reg, uint8_t *value) { + return sx127x_single_transfer(handle, reg & 0x7f, 0x00, value); +} + +esp_err_t sx127x_write_register(sx127x_t *handle, uint8_t reg, uint8_t value) { + return sx127x_single_transfer(handle, reg | 0x80, value, NULL); +} + +esp_err_t sx127x_single_transfer(sx127x_t *handle, uint8_t addr, uint8_t to_slave, uint8_t *from_slave) { + spi_transaction_t trans; + memset(&trans, 0, sizeof(trans)); + trans.flags = SPI_TRANS_USE_RXDATA | SPI_TRANS_USE_TXDATA; + trans.addr = addr; + trans.length = 8; + trans.rxlength = 8; + trans.tx_data[0] = to_slave; + + esp_err_t ret = spi_device_transmit(handle->device_handle, &trans); + SX127X_ERROR_CHECK2(ret, spi_device_transmit); + if (from_slave) { + *from_slave = trans.rx_data[0]; + } + ESP_LOGV(SX127X_TAG, "sx127x_single_transfer(%#x, %#x, %#x)", addr, trans.tx_data[0], trans.rx_data[0]); + return ESP_OK; +} + +esp_err_t sx127x_sleep(sx127x_t *handle) { + return sx127x_write_register(handle, REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_SLEEP); +} + +esp_err_t sx127x_standby(sx127x_t *handle) { + return sx127x_write_register(handle, REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_STDBY); +} + +esp_err_t sx127x_set_frequency(sx127x_t *handle, uint64_t frequency) { + uint64_t frf = ((uint64_t)frequency << 19) / 32000000; + esp_err_t ret; + + ret = sx127x_write_register(handle, REG_FRF_MSB, (uint8_t)(frf)); + SX127X_ERROR_CHECK(ret); + frf >>= 8; + ret = sx127x_write_register(handle, REG_FRF_MID, (uint8_t)(frf)); + SX127X_ERROR_CHECK(ret); + frf >>= 8; + ret = sx127x_write_register(handle, REG_FRF_LSB, (uint8_t)(frf)); + SX127X_ERROR_CHECK(ret); + + handle->config.frequency = frequency; + return ESP_OK; +} + +esp_err_t sx127x_set_tx_power(sx127x_t *handle, uint8_t tx_power, sx127x_pa_boost_t pa_boost) { + esp_err_t ret; + if (pa_boost == SX127X_PA_BOOST_ENABLED) { + // PA BOOST + SX127X_CHECK(tx_power >= 2 && tx_power <= 20, "invalid tx_power: %d", ESP_ERR_INVALID_ARG, tx_power); + ret = sx127x_write_register(handle, REG_PA_CONFIG, PA_BOOST | (tx_power - 2)); + } else { + // RFO + SX127X_CHECK(tx_power <= 14, "invalid tx_power: %d", ESP_ERR_INVALID_ARG, tx_power); + ret = sx127x_write_register(handle, REG_PA_CONFIG, 0x70 | tx_power); + } + SX127X_ERROR_CHECK(ret); + + handle->config.tx_power = tx_power; + return ESP_OK; +} + +esp_err_t sx127x_set_spreading_factor(sx127x_t *handle, uint8_t spreading_factor) { + SX127X_CHECK(spreading_factor >= 6 && spreading_factor <= 12, "invalid spreading_factor", ESP_ERR_INVALID_ARG); + // section 4.1.1.2 in SX1276 datasheet + uint8_t detection_optimize, detection_threshold; + if (spreading_factor == 6) { + detection_optimize = 0xc5; + detection_threshold = 0x0c; + } else { + detection_optimize = 0xc3; + detection_threshold = 0x0a; + } + SX127X_ERROR_CHECK(sx127x_write_register(handle, REG_DETECTION_OPTIMIZE, detection_optimize)); + SX127X_ERROR_CHECK(sx127x_write_register(handle, REG_DETECTION_THRESHOLD, detection_threshold)); + + uint8_t modem_config_3; + SX127X_ERROR_CHECK(sx127x_read_register(handle, REG_MODEM_CONFIG_3, &modem_config_3)); + modem_config_3 = (modem_config_3 & 0x03) | ((spreading_factor << 4) & 0xf0); + SX127X_ERROR_CHECK(sx127x_write_register(handle, REG_MODEM_CONFIG_3, modem_config_3)); + + handle->config.spreading_factor = spreading_factor; + return ESP_OK; +} + +esp_err_t sx127x_set_signal_bandwidth(sx127x_t *handle, uint64_t signal_bandwidth) { + uint8_t bw_reg = sx127x_bw_to_reg(signal_bandwidth); + uint8_t modem_config_1; + SX127X_ERROR_CHECK(sx127x_read_register(handle, REG_MODEM_CONFIG_1, &modem_config_1)); + modem_config_1 = (modem_config_1 & 0x0f) | (bw_reg << 4); + SX127X_ERROR_CHECK(sx127x_write_register(handle, REG_MODEM_CONFIG_1, modem_config_1)); + handle->config.signal_bandwidth = signal_bandwidth; + + // set low data rate optimization flag + uint64_t bw = sx127x_reg_to_bw(bw_reg); + uint8_t sf = handle->config.spreading_factor; + // section 4.1.1.5 + uint64_t symbol_duration_ms = 1000 / (bw / (1L << sf)); + + // section 4.1.1.6 + bool must_have_ldo = (symbol_duration_ms > 16); + bool ldo = must_have_ldo || (handle->config.ldo == SX127X_LDO_ENABLED); + + uint8_t modem_config_3; + SX127X_ERROR_CHECK(sx127x_read_register(handle, REG_MODEM_CONFIG_3, &modem_config_3)); + if (ldo) { + modem_config_3 |= (1 << 3); + } else { + modem_config_3 &= ~(1 << 3); + } + SX127X_ERROR_CHECK(sx127x_write_register(handle, REG_MODEM_CONFIG_3, modem_config_3)); + + return ESP_OK; +} + +uint8_t sx127x_bw_to_reg(uint64_t bandwidth) { + if (bandwidth <= 7.8E3) { + return 0; + } else if (bandwidth <= 10.4E3) { + return 1; + } else if (bandwidth <= 15.6E3) { + return 2; + } else if (bandwidth <= 20.8E3) { + return 3; + } else if (bandwidth <= 31.25E3) { + return 4; + } else if (bandwidth <= 41.7E3) { + return 5; + } else if (bandwidth <= 62.5E3) { + return 6; + } else if (bandwidth <= 125E3) { + return 7; + } else if (bandwidth <= 250E3) { + return 8; + } else /* if (bandwidth <= 500E3) */ { + return 9; + } +} + +uint64_t sx127x_reg_to_bw(uint8_t bandwidth_reg) { + switch (bandwidth_reg) { + case 0: return 7.8E3; + case 1: return 10.4E3; + case 2: return 15.6E3; + case 3: return 20.8E3; + case 4: return 31.25E3; + case 5: return 41.7E3; + case 6: return 62.5E3; + case 7: return 125E3; + case 8: return 250E3; + default: + case 9: return 500E3; + } +} + +esp_err_t sx127x_set_sync_word(sx127x_t *handle, uint8_t sync_word) { + SX127X_ERROR_CHECK(sx127x_write_register(handle, REG_SYNC_WORD, sync_word)); + handle->config.sync_word = sync_word; + return ESP_OK; +} + +esp_err_t sx127x_set_crc(sx127x_t *handle, sx127x_crc_t crc) { + uint8_t modem_config_2; + SX127X_ERROR_CHECK(sx127x_read_register(handle, REG_MODEM_CONFIG_2, &modem_config_2)); + if (crc == SX127X_CRC_ENABLED) { + modem_config_2 |= CONFIG2_CRC; + } else { + modem_config_2 &= ~CONFIG2_CRC; + } + SX127X_ERROR_CHECK(sx127x_write_register(handle, REG_MODEM_CONFIG_2, modem_config_2)); + handle->config.crc = crc; + return ESP_OK; +} diff --git a/components/sx127x_driver/sx127x_registers.h b/components/sx127x_driver/sx127x_registers.h new file mode 100644 index 0000000..5c604b4 --- /dev/null +++ b/components/sx127x_driver/sx127x_registers.h @@ -0,0 +1,20 @@ +#include "sx127x_driver.h" + +esp_err_t sx127x_read_register(sx127x_t *handle, uint8_t reg, uint8_t *value); +esp_err_t sx127x_write_register(sx127x_t *handle, uint8_t reg, uint8_t value); +esp_err_t sx127x_single_transfer(sx127x_t *handle, uint8_t addr, uint8_t to_slave, uint8_t *from_slave); + +uint8_t sx127x_bw_to_reg(uint64_t bandwidth); +uint64_t sx127x_reg_to_bw(uint8_t bandwidth_reg); + +esp_err_t sx127x_set_frequency(sx127x_t *handle, uint64_t frequency); + +esp_err_t sx127x_set_tx_power(sx127x_t *handle, uint8_t tx_power, sx127x_pa_boost_t pa_boost); + +esp_err_t sx127x_set_spreading_factor(sx127x_t *handle, uint8_t spreading_factor); + +esp_err_t sx127x_set_signal_bandwidth(sx127x_t *handle, uint64_t signal_bandwidth); + +esp_err_t sx127x_set_sync_word(sx127x_t *handle, uint8_t sync_word); + +esp_err_t sx127x_set_crc(sx127x_t *handle, sx127x_crc_t crc); diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt index 7accae5..91db78e 100644 --- a/main/CMakeLists.txt +++ b/main/CMakeLists.txt @@ -1,9 +1,7 @@ set(COMPONENT_SRCS "ugv_main.c" - "u8g2_esp32_hal.c" - "sx127x_driver/sx127x_driver.c") -set(COMPONENT_ADD_INCLUDEDIRS "." - "./sx127x_driver") -set(COMPONENT_REQUIRES "u8g2") + "u8g2_esp32_hal.c") +set(COMPONENT_ADD_INCLUDEDIRS ".") +set(COMPONENT_REQUIRES "u8g2" "sx127x_driver") register_component() diff --git a/main/sx127x_driver/sx127x_driver.c b/main/sx127x_driver/sx127x_driver.c deleted file mode 100644 index cd3f9ad..0000000 --- a/main/sx127x_driver/sx127x_driver.c +++ /dev/null @@ -1,468 +0,0 @@ -#include "sx127x_driver.h" - -#include -#include -#include - -static const char *TAG = "sx127x"; - -#define MAX_PKT_LENGTH 255 -#define RESET_DELAY (pdMS_TO_TICKS(15)) -// 8mhz -#define SPI_CLOCK_HZ (8 * 1000 * 1000) -#define TASK_STACK_SIZE (2 * 1024) -#define TASK_PRIORITY 3 - -#define REG_FIFO 0x00 -#define REG_OP_MODE 0x01 -#define REG_FRF_MSB 0x06 -#define REG_FRF_MID 0x07 -#define REG_FRF_LSB 0x08 -#define REG_PA_CONFIG 0x09 -#define REG_OCP 0x0b -#define REG_LNA 0x0c -#define REG_FIFO_ADDR_PTR 0x0d -#define REG_FIFO_TX_BASE_ADDR 0x0e -#define REG_FIFO_RX_BASE_ADDR 0x0f -#define REG_FIFO_RX_CURRENT_ADDR 0x10 -#define REG_IRQ_FLAGS 0x12 -#define REG_RX_NB_BYTES 0x13 -#define REG_PKT_SNR_VALUE 0x19 -#define REG_PKT_RSSI_VALUE 0x1a -#define REG_MODEM_CONFIG_1 0x1d -#define REG_MODEM_CONFIG_2 0x1e -#define REG_PREAMBLE_MSB 0x20 -#define REG_PREAMBLE_LSB 0x21 -#define REG_PAYLOAD_LENGTH 0x22 -#define REG_MODEM_CONFIG_3 0x26 -#define REG_FREQ_ERROR_MSB 0x28 -#define REG_FREQ_ERROR_MID 0x29 -#define REG_FREQ_ERROR_LSB 0x2a -#define REG_RSSI_WIDEBAND 0x2c -#define REG_DETECTION_OPTIMIZE 0x31 -#define REG_INVERTIQ 0x33 -#define REG_DETECTION_THRESHOLD 0x37 -#define REG_SYNC_WORD 0x39 -#define REG_INVERTIQ2 0x3b -#define REG_DIO_MAPPING_1 0x40 -#define REG_VERSION 0x42 -#define REG_PA_DAC 0x4d - -// modes -#define MODE_LONG_RANGE_MODE 0x80 -#define MODE_SLEEP 0x00 -#define MODE_STDBY 0x01 -#define MODE_TX 0x03 -#define MODE_RX_CONTINUOUS 0x05 -#define MODE_RX_SINGLE 0x06 - -#define CONFIG2_CRC 0x04 -#define CONFIG3_AUTO_AGC 0x04 - -// PA config -#define PA_BOOST 0x80 - -// IRQ masks -#define IRQ_TX_DONE_MASK 0x08 -#define IRQ_PAYLOAD_CRC_ERROR_MASK 0x20 -#define IRQ_RX_DONE_MASK 0x40 - -#ifdef NODEBUG -#define SX127X_CHECK(check, str, ret_val, ...) \ - if (!(check)) { \ - ESP_LOGE(TAG, "%s(%d): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__); \ - return (ret_val); \ - } -#define SX127X_ERROR_CHECK(ret) \ - { \ - esp_err_t _error_code = (ret); \ - if (_error_code != ESP_OK) { \ - return _error_code; \ - } \ - } -#define SX127X_ERROR_CHECK2(ret, fun) SX127X_CHECK(ret) -#else -#define SX127X_CHECK(check, str, ret_val, ...) \ - if (!(check)) { \ - ESP_LOGE(TAG, "%s(%d): " #check ": " str, __FUNCTION__, __LINE__, ##__VA_ARGS__); \ - return (ret_val); \ - } -#define SX127X_ERROR_CHECK(ret) \ - { \ - esp_err_t _error_code = (ret); \ - if (_error_code != ESP_OK) { \ - const char *_error_name = esp_err_to_name(_error_code); \ - ESP_LOGE(TAG, "%s(%d): %s (%d)", __FUNCTION__, __LINE__, _error_name, _error_code); \ - return _error_code; \ - } \ - } -#define SX127X_ERROR_CHECK2(ret, fun) \ - { \ - esp_err_t _error_code = (ret); \ - if (_error_code != ESP_OK) { \ - const char *_error_name = esp_err_to_name(_error_code); \ - ESP_LOGE(TAG, "%s(%d): " #fun ": %s (%d)", __FUNCTION__, __LINE__, _error_name, _error_code); \ - return _error_code; \ - } \ - } -#endif - -struct sx127x { - sx127x_config_t config; - spi_device_handle_t device_handle; - TaskHandle_t task_handle; - bool task_running; -}; - -static esp_err_t sx127x_read_register(sx127x_t *handle, uint8_t reg, uint8_t *value); -static esp_err_t sx127x_write_register(sx127x_t *handle, uint8_t reg, uint8_t value); -static esp_err_t sx127x_single_transfer(sx127x_t *handle, uint8_t addr, uint8_t to_slave, uint8_t *from_slave); - -static uint8_t sx127x_bw_to_reg(uint64_t bandwidth); -static uint64_t sx127x_reg_to_bw(uint8_t bandwidth_reg); - -esp_err_t sx127x_init(sx127x_config_t *config, sx127x_t **handle_ptr) { - esp_err_t ret; - sx127x_t *handle = malloc(sizeof(sx127x_t)); - SX127X_CHECK(handle != NULL, "malloc error", ESP_ERR_NO_MEM); - - handle->task_handle = NULL; - memcpy(&handle->config, config, sizeof(sx127x_config_t)); - - ret = gpio_set_direction(config->rst_io_num, GPIO_MODE_OUTPUT); - SX127X_ERROR_CHECK2(ret, gpio_set_direction) - - // perform reset - gpio_set_level(config->rst_io_num, 0); - vTaskDelay(RESET_DELAY); - gpio_set_level(config->rst_io_num, 1); - vTaskDelay(RESET_DELAY); - - spi_bus_config_t bus_config = {.mosi_io_num = config->mosi_io_num, - .miso_io_num = config->miso_io_num, - .sclk_io_num = config->sck_io_num, - .quadhd_io_num = -1, - .quadwp_io_num = -1, - .max_transfer_sz = SX127X_MAX_TRANSFER}; - ret = spi_bus_initialize(config->spi_host, &bus_config, 1); - SX127X_ERROR_CHECK2(ret, spi_bus_initialize) - - spi_device_interface_config_t device_config = { - .command_bits = 0, - .address_bits = 8, - .dummy_bits = 0, - .mode = 0, - .duty_cycle_pos = 0, - .cs_ena_pretrans = 0, - .cs_ena_posttrans = 0, - .clock_speed_hz = SPI_CLOCK_HZ, // 8mhz - .input_delay_ns = 0, - .spics_io_num = config->cs_io_num, - .flags = 0, - .queue_size = 8, - .pre_cb = NULL, - .post_cb = NULL, - }; - ret = spi_bus_add_device(config->spi_host, &device_config, &handle->device_handle); - SX127X_ERROR_CHECK2(ret, spi_bus_add_device) - - // read version and check that it is compatible - uint8_t version; - ret = sx127x_read_register(handle, REG_VERSION, &version); - SX127X_ERROR_CHECK2(ret, sx127x_read_register); - SX127X_CHECK(version == 0x12, "unsupported version %#x", ESP_ERR_INVALID_VERSION, version); - - ret = sx127x_sleep(handle); - SX127X_ERROR_CHECK(ret); - - ret = sx127x_set_frequency(handle, config->frequency); - SX127X_ERROR_CHECK(ret); - - ret = sx127x_write_register(handle, REG_FIFO_TX_BASE_ADDR, 0); - SX127X_ERROR_CHECK(ret); - sx127x_write_register(handle, REG_FIFO_RX_BASE_ADDR, 0); - SX127X_ERROR_CHECK(ret); - - uint8_t reg_lna; - ret = sx127x_read_register(handle, REG_LNA, ®_lna); - SX127X_ERROR_CHECK(ret); - reg_lna |= 0x03; // set LNA boost - ret = sx127x_write_register(handle, REG_LNA, reg_lna); - SX127X_ERROR_CHECK(ret); - - // set auto AGC - ret = sx127x_write_register(handle, REG_MODEM_CONFIG_3, CONFIG3_AUTO_AGC); - SX127X_ERROR_CHECK(ret); - - ret = sx127x_set_tx_power(handle, config->tx_power, true); - SX127X_ERROR_CHECK(ret); - - ret = sx127x_set_spreading_factor(handle, config->spreading_factor); - SX127X_ERROR_CHECK(ret); - - ret = sx127x_set_sync_word(handle, config->sync_word); - SX127X_ERROR_CHECK(ret); - - ret = sx127x_set_crc(handle, config->crc); - SX127X_ERROR_CHECK(ret); - - ret = sx127x_standby(handle); - ESP_ERROR_CHECK(ret); - - *handle_ptr = handle; - return ESP_OK; -} - -esp_err_t sx127x_free(sx127x_t *handle) { - esp_err_t ret; - - if (handle->task_handle) { - ret = sx127x_stop(handle); - SX127X_ERROR_CHECK(ret); - } - - ret = spi_bus_remove_device(handle->device_handle); - SX127X_ERROR_CHECK2(ret, spi_bus_remove_device) - - ret = spi_bus_free(handle->config.spi_host); - SX127X_ERROR_CHECK2(ret, spi_bus_free) - - free(handle); - - return ESP_OK; -} - -static esp_err_t sx127x_read_register(sx127x_t *handle, uint8_t reg, uint8_t *value) { - return sx127x_single_transfer(handle, reg & 0x7f, 0x00, value); -} - -static esp_err_t sx127x_write_register(sx127x_t *handle, uint8_t reg, uint8_t value) { - return sx127x_single_transfer(handle, reg | 0x80, value, NULL); -} - -static esp_err_t sx127x_single_transfer(sx127x_t *handle, uint8_t addr, uint8_t to_slave, uint8_t *from_slave) { - spi_transaction_t trans; - memset(&trans, 0, sizeof(trans)); - trans.flags = SPI_TRANS_USE_RXDATA | SPI_TRANS_USE_TXDATA; - trans.addr = addr; - trans.length = 8; - trans.rxlength = 8; - trans.tx_data[0] = to_slave; - - esp_err_t ret = spi_device_transmit(handle->device_handle, &trans); - SX127X_ERROR_CHECK2(ret, spi_device_transmit); - if (from_slave) { - *from_slave = trans.rx_data[0]; - } - ESP_LOGV(TAG, "sx127x_single_transfer(%#x, %#x, %#x)", addr, trans.tx_data[0], trans.rx_data[0]); - return ESP_OK; -} - -esp_err_t sx127x_sleep(sx127x_t *handle) { - return sx127x_write_register(handle, REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_SLEEP); -} - -esp_err_t sx127x_standby(sx127x_t *handle) { - return sx127x_write_register(handle, REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_STDBY); -} - -esp_err_t sx127x_set_frequency(sx127x_t *handle, uint64_t frequency) { - uint64_t frf = ((uint64_t)frequency << 19) / 32000000; - esp_err_t ret; - - ret = sx127x_write_register(handle, REG_FRF_MSB, (uint8_t)(frf)); - SX127X_ERROR_CHECK(ret); - frf >>= 8; - ret = sx127x_write_register(handle, REG_FRF_MID, (uint8_t)(frf)); - SX127X_ERROR_CHECK(ret); - frf >>= 8; - ret = sx127x_write_register(handle, REG_FRF_LSB, (uint8_t)(frf)); - SX127X_ERROR_CHECK(ret); - - handle->config.frequency = frequency; - return ESP_OK; -} - -esp_err_t sx127x_set_tx_power(sx127x_t *handle, uint8_t tx_power, sx127x_pa_boost_t pa_boost) { - esp_err_t ret; - if (pa_boost == SX127X_PA_BOOST_ENABLED) { - // PA BOOST - SX127X_CHECK(tx_power >= 2 && tx_power <= 20, "invalid tx_power: %d", ESP_ERR_INVALID_ARG, tx_power); - ret = sx127x_write_register(handle, REG_PA_CONFIG, PA_BOOST | (tx_power - 2)); - } else { - // RFO - SX127X_CHECK(tx_power <= 14, "invalid tx_power: %d", ESP_ERR_INVALID_ARG, tx_power); - ret = sx127x_write_register(handle, REG_PA_CONFIG, 0x70 | tx_power); - } - SX127X_ERROR_CHECK(ret); - - handle->config.tx_power = tx_power; - return ESP_OK; -} - -esp_err_t sx127x_set_spreading_factor(sx127x_t *handle, uint8_t spreading_factor) { - SX127X_CHECK(spreading_factor >= 6 && spreading_factor <= 12, "invalid spreading_factor", ESP_ERR_INVALID_ARG); - // section 4.1.1.2 in SX1276 datasheet - uint8_t detection_optimize, detection_threshold; - if (spreading_factor == 6) { - detection_optimize = 0xc5; - detection_threshold = 0x0c; - } else { - detection_optimize = 0xc3; - detection_threshold = 0x0a; - } - SX127X_ERROR_CHECK(sx127x_write_register(handle, REG_DETECTION_OPTIMIZE, detection_optimize)); - SX127X_ERROR_CHECK(sx127x_write_register(handle, REG_DETECTION_THRESHOLD, detection_threshold)); - - uint8_t modem_config_3; - SX127X_ERROR_CHECK(sx127x_read_register(handle, REG_MODEM_CONFIG_3, &modem_config_3)); - modem_config_3 = (modem_config_3 & 0x03) | ((spreading_factor << 4) & 0xf0); - SX127X_ERROR_CHECK(sx127x_write_register(handle, REG_MODEM_CONFIG_3, modem_config_3)); - - handle->config.spreading_factor = spreading_factor; - return ESP_OK; -} - -esp_err_t sx127x_set_signal_bandwidth(sx127x_t *handle, uint64_t signal_bandwidth) { - uint8_t bw_reg = sx127x_bw_to_reg(signal_bandwidth); - uint8_t modem_config_1; - SX127X_ERROR_CHECK(sx127x_read_register(handle, REG_MODEM_CONFIG_1, &modem_config_1)); - modem_config_1 = (modem_config_1 & 0x0f) | (bw_reg << 4); - SX127X_ERROR_CHECK(sx127x_write_register(handle, REG_MODEM_CONFIG_1, modem_config_1)); - handle->config.signal_bandwidth = signal_bandwidth; - - // set low data rate optimization flag - uint64_t bw = sx127x_reg_to_bw(bw_reg); - uint8_t sf = handle->config.spreading_factor; - // section 4.1.1.5 - uint64_t symbol_duration_ms = 1000 / (bw / (1L << sf)); - - // section 4.1.1.6 - bool must_have_ldo = (symbol_duration_ms > 16); - bool ldo = must_have_ldo || (handle->config.ldo == SX127X_LDO_ENABLED); - - uint8_t modem_config_3; - SX127X_ERROR_CHECK(sx127x_read_register(handle, REG_MODEM_CONFIG_3, &modem_config_3)); - if (ldo) { - modem_config_3 |= (1 << 3); - } else { - modem_config_3 &= ~(1 << 3); - } - SX127X_ERROR_CHECK(sx127x_write_register(handle, REG_MODEM_CONFIG_3, modem_config_3)); - - return ESP_OK; -} - -static uint8_t sx127x_bw_to_reg(uint64_t bandwidth) { - if (bandwidth <= 7.8E3) { - return 0; - } else if (bandwidth <= 10.4E3) { - return 1; - } else if (bandwidth <= 15.6E3) { - return 2; - } else if (bandwidth <= 20.8E3) { - return 3; - } else if (bandwidth <= 31.25E3) { - return 4; - } else if (bandwidth <= 41.7E3) { - return 5; - } else if (bandwidth <= 62.5E3) { - return 6; - } else if (bandwidth <= 125E3) { - return 7; - } else if (bandwidth <= 250E3) { - return 8; - } else /* if (bandwidth <= 500E3) */ { - return 9; - } -} -static uint64_t sx127x_reg_to_bw(uint8_t bandwidth_reg) { - switch (bandwidth_reg) { - case 0: return 7.8E3; - case 1: return 10.4E3; - case 2: return 15.6E3; - case 3: return 20.8E3; - case 4: return 31.25E3; - case 5: return 41.7E3; - case 6: return 62.5E3; - case 7: return 125E3; - case 8: return 250E3; - default: - case 9: return 500E3; - } -} - -esp_err_t sx127x_set_sync_word(sx127x_t *handle, uint8_t sync_word) { - SX127X_ERROR_CHECK(sx127x_write_register(handle, REG_SYNC_WORD, sync_word)); - handle->config.sync_word = sync_word; - return ESP_OK; -} - -esp_err_t sx127x_set_crc(sx127x_t *handle, sx127x_crc_t crc) { - uint8_t modem_config_2; - SX127X_ERROR_CHECK(sx127x_read_register(handle, REG_MODEM_CONFIG_2, &modem_config_2)); - if (crc == SX127X_CRC_ENABLED) { - modem_config_2 |= CONFIG2_CRC; - } else { - modem_config_2 &= ~CONFIG2_CRC; - } - SX127X_ERROR_CHECK(sx127x_write_register(handle, REG_MODEM_CONFIG_2, modem_config_2)); - handle->config.crc = crc; - return ESP_OK; -} - -void sx127x_isr(void *arg) { - sx127x_t *handle = (sx127x_t *)arg; - ESP_LOGI(TAG, "sx127x_isr"); -} - -void sx127x_task(void *arg) { - sx127x_t *handle = (sx127x_t *)arg; - while (handle->task_running) { - vTaskDelay(pdMS_TO_TICKS(10)); - } -} - -esp_err_t sx127x_start(sx127x_t *handle) { - esp_err_t ret; - - SX127X_CHECK(handle->task_handle == NULL, "task already running", ESP_ERR_INVALID_STATE); - - ret = sx127x_write_register(handle, REG_DIO_MAPPING_1, 0x00); - SX127X_ERROR_CHECK(ret); - - gpio_config_t irq_io_config; - irq_io_config.intr_type = GPIO_INTR_POSEDGE; - irq_io_config.mode = GPIO_MODE_INPUT; - irq_io_config.pin_bit_mask = (1ULL << handle->config.irq_io_num); - irq_io_config.pull_down_en = 0; - irq_io_config.pull_up_en = 0; - ret = gpio_config(&irq_io_config); - SX127X_ERROR_CHECK2(ret, gpio_config) - - ret = gpio_install_isr_service(ESP_INTR_FLAG_LEVEL1); - SX127X_ERROR_CHECK2(ret, gpio_install_isr_service); - ret = gpio_isr_handler_add(handle->config.irq_io_num, sx127x_isr, (void *)handle); - SX127X_ERROR_CHECK2(ret, gpio_isr_handler_add); - - handle->task_running = true; - - BaseType_t pdRet = - xTaskCreate(sx127x_task, "sx127x_task", TASK_STACK_SIZE, (void *)handle, TASK_PRIORITY, &handle->task_handle); - SX127X_CHECK(pdRet == pdPASS, "failed to create task", ESP_FAIL); - return ESP_OK; -} - -esp_err_t sx127x_stop(sx127x_t *handle) { - esp_err_t ret; - - SX127X_CHECK(handle->task_handle != NULL, "task has not been started", ESP_ERR_INVALID_STATE); - handle->task_running = false; - xTaskNotify(handle->task_handle, 0, eNoAction); - - ret = gpio_isr_handler_remove(handle->config.irq_io_num); - SX127X_ERROR_CHECK2(ret, gpio_isr_handler_remove); - gpio_uninstall_isr_service(); - - return ESP_OK; -} \ No newline at end of file