manuelbl / ttn-esp32

The Things Network device library for ESP32 (ESP-IDF) and SX127x based devices
MIT License
308 stars 64 forks source link

Wemos D1 R32 and Dragino Lora shield -> LMIC error #23

Closed cc32d9 closed 4 years ago

cc32d9 commented 4 years ago

I'm trying to run a simple example on Wemos D1 R32 board with Dragino Lora shield. This example worked with TTGO boards without issues.

https://wiki.dragino.com/index.php?title=Lora_Shield

SV2, SV3, SV4 jumpers are on the left

J_DIO1 jumper is connected, and two other DIO jumpers disconnected.

The Wemos uses its own GPIO numbers mapped to Uno pins, and the configuration works with a simple Lora example that does not use LMIC. The following is configured:

#define TTN_SPI_HOST      VSPI_HOST
#define TTN_SPI_DMA_CHAN  1
#define TTN_PIN_SPI_SCLK  18
#define TTN_PIN_SPI_MOSI  23
#define TTN_PIN_SPI_MISO  19
#define TTN_PIN_NSS       5
#define TTN_PIN_RXTX      TTN_NOT_CONNECTED
#define TTN_PIN_RST       13
#define TTN_PIN_DIO0      26
#define TTN_PIN_DIO1      27

The board produces an error immediately at start. The same error ocurs if the LoRa shield is removed completely:

I (220) boot: Loaded app from partition at offset 0x10000
I (220) boot: Disabling RNG early entropy source...
I (221) cpu_start: Pro cpu up.
I (224) cpu_start: Application information:
I (229) cpu_start: Project name:     datasender
I (235) cpu_start: App version:      1764376-dirty
I (240) cpu_start: Compile time:     May 20 2020 00:49:52
I (246) cpu_start: ELF file SHA256:  241a3510def0045d...
I (252) cpu_start: ESP-IDF:          v4.2-dev-1575-ga3520970f-dirty
I (259) cpu_start: Starting app cpu, entry point is 0x400817a4
0x400817a4: call_start_cpu1 at /opt/esp/esp-idf/components/esp32/cpu_start.c:286

I (0) cpu_start: App cpu up.
I (269) heap_init: Initializing. RAM available for dynamic allocation:
I (276) heap_init: At 3FFAE6E0 len 00001920 (6 KiB): DRAM
I (282) heap_init: At 3FFB30B0 len 0002CF50 (179 KiB): DRAM
I (289) heap_init: At 3FFE0440 len 00003AE0 (14 KiB): D/IRAM
I (295) heap_init: At 3FFE4350 len 0001BCB0 (111 KiB): D/IRAM
I (301) heap_init: At 4008C058 len 00013FA8 (79 KiB): IRAM
I (308) cpu_start: Pro cpu start user code
I (326) spi_flash: detected chip: generic
I (326) spi_flash: flash io: dio
I (326) cpu_start: Starting scheduler on PRO CPU.
I (0) cpu_start: Starting scheduler on APP CPU.
I (350) ttn_hal: IO initialized
I (350) ttn_hal: SPI initialized
I (350) ttn_hal: Timer initialized
E (360) ttn_hal: LMIC failed and stopped: ../components/ttn-esp32/src/lmic/radio.c:1147
cc32d9 commented 4 years ago

the Lora example doesn't use DIO pins, so probably the problem lays in them. But they are mapped and connected to respective GPIO pins.

manuelbl commented 4 years ago

From your description, it seems that the pins are correctly mapped. Yet I don't have your hardware and can't verify it.

the Lora example doesn't use DIO pins, so probably the problem lays in them. But they are mapped and connected to respective GPIO pins.

I don't understand this statement. DIO0 and DIO1 are always needed. Anyway, your code seems to fail before these signals become relevant.

The most likely cause is that the SPI communication between the ESP-32 and the RFM95W is not working proplerly.

What version of the ttn-esp32 library are you using? The one from the dev branch?

cc32d9 commented 4 years ago

I don't understand this statement. DIO0 and DIO1 are always needed. Anyway, your code seems to fail before these signals become relevant.

I mean I compiled a different example, not using your library, and it talks to Lora chip directly. It is able to send and receive packets on this hardware, and it's not using DIO pins.

I also tried to ad pull-up resistors to DIO0 and DIO1, but it didn't help.

It's dev branch of ttn-esp32, and latest master branch of esp-idf.

Are you located in Europe? A couple of such hardware kits are on the way to me, and I can send you one as soon as they arrive.

manuelbl commented 4 years ago

Forget about DIO0 and DIO1 at the moment. Your code most likely didn't get far enough to use them. Investigate the SPI communication instead. For example, try to read the chip version number:

void hal_spi_read(uint8_t cmd, uint8_t * buf, size_t len);

uint8_t buf[1];
hal_spi_read(0x42 & 0x7f, buf, 1);
ASSERT(buf[0] == 0x12);

dev branch is good.

cc32d9 commented 4 years ago
    err = spi_bus_initialize(TTN_SPI_HOST, &spi_bus_config, TTN_SPI_DMA_CHAN);
    ESP_ERROR_CHECK(err);

    uint8_t buf[1];
    hal_spi_read(0x42 & 0x7f, buf, 1);
    printf("Read from SPI: %x\n", buf[0]);

    // Configure the SX127x pins
    ttn.configurePins(TTN_SPI_HOST, TTN_PIN_NSS, TTN_PIN_RXTX, TTN_PIN_RST, TTN_PIN_DIO0, TTN_PIN_DIO1);

didn't work well:

I (326) spi_flash: detected chip: generic
I (327) spi_flash: flash io: dio
I (327) cpu_start: Starting scheduler on PRO CPU.
I (0) cpu_start: Starting scheduler on APP CPU.
E (356) spi_master: check_trans_valid(663): invalid dev handle
ESP_ERROR_CHECK failed: esp_err_t 0x102 (ESP_ERR_INVALID_ARG) at 0x40084dac
0x40084dac: _esp_error_check_failed at /opt/esp/esp-idf/components/esp_common/src/esp_err.c:45

file: "../components/ttn-esp32/src/hal/hal_esp32.cpp" line 210
func: void HAL_ESP32::spiRead(uint8_t, uint8_t*, size_t)
expression: err

abort() was called at PC 0x40084daf on core 0
0x40084daf: _esp_error_check_failed at /opt/esp/esp-idf/components/esp_common/src/esp_err.c:46

Backtrace:0x40085213:0x3ffb4e10 0x4008583d:0x3ffb4e30 0x400892fe:0x3ffb4e50 0x40084daf:0x3ffb4ec0 0x400d3ba1:0x3ffb4ee0 0x400d3bb5:0x3ffb4f00 0x400d3671:0x3ffb4f20 0x400d1fc6:0x3ffb4f80 0x40085845:0x3ffb4fb0
0x40085213: panic_abort at /opt/esp/esp-idf/components/esp_system/panic.c:330

0x4008583d: esp_system_abort at /opt/esp/esp-idf/components/esp_system/system_api.c:100

0x400892fe: abort at /opt/esp/esp-idf/components/newlib/abort.c:46

0x40084daf: _esp_error_check_failed at /opt/esp/esp-idf/components/esp_common/src/esp_err.c:46

0x400d3ba1: HAL_ESP32::spiRead(unsigned char, unsigned char*, unsigned int) at /opt/esp/build/ttn/datasender/build/../components/ttn-esp32/src/hal/hal_esp32.cpp:210 (discriminator 1)

0x400d3bb5: hal_spi_read at /opt/esp/build/ttn/datasender/build/../components/ttn-esp32/src/hal/hal_esp32.cpp:197

0x400d3671: app_main at /opt/esp/build/ttn/datasender/build/../main/datasender.cpp:84

0x400d1fc6: main_task at /opt/esp/esp-idf/components/esp32/cpu_start.c:580

0x40085845: vPortTaskWrapper at /opt/esp/esp-idf/components/freertos/xtensa/port.c:143
cc32d9 commented 4 years ago

same if I insert it in TheThingsNetwork::configurePins after ttn_hal.configurePins

manuelbl commented 4 years ago

Sorry, the code I've provided cannot work. It's missing essential initialization as you have figured out yourself. I'll provide updated code later.

manuelbl commented 4 years ago

Here's the updated code. It should be inserted after the initialization of the SPI bus:

    gpio_pad_select_gpio(TTN_PIN_NSS);
    gpio_set_level((gpio_num_t)TTN_PIN_NSS, 0);
    gpio_set_direction((gpio_num_t)TTN_PIN_NSS, GPIO_MODE_OUTPUT);

    // init device
    spi_device_interface_config_t spiConfig;
    memset(&spiConfig, 0, sizeof(spiConfig));
    spiConfig.mode = 0;
    spiConfig.clock_speed_hz = 1000000;
    spiConfig.command_bits = 0;
    spiConfig.address_bits = 8;
    spiConfig.spics_io_num = TTN_PIN_NSS;
    spiConfig.queue_size = 1;
    spiConfig.cs_ena_pretrans = 0;
    spiConfig.cs_ena_posttrans = 3;

    spi_device_handle_t spiHandle;
    esp_err_t ret = spi_bus_add_device(TTN_SPI_HOST, &spiConfig, &spiHandle);
    ESP_ERROR_CHECK(ret);

    uint8_t buf[4];
    memset(buf, 0, sizeof(buf));
    spi_transaction_t spiTransaction;
    memset(&spiTransaction, 0, sizeof(spiTransaction));
    spiTransaction.addr = 0x42;
    spiTransaction.length = 8;
    spiTransaction.rxlength = 8;
    spiTransaction.tx_buffer = buf;
    spiTransaction.rx_buffer = buf;
    err = spi_device_transmit(spiHandle, &spiTransaction);
    ESP_ERROR_CHECK(err);

    ESP_LOGI("test", "Version: 0x%02x", buf[0]);

You might need additional includes:

#include <string.h>
#include "esp_log.h"

The symptoms you are seeing indeed indicate that the SPI communication is not working. I've verified it. So check the wiring of SCK, MISO, MOSI and NSS:

cc32d9 commented 4 years ago
I (308) cpu_start: Pro cpu start user code
I (326) spi_flash: detected chip: generic
I (327) spi_flash: flash io: dio
I (327) cpu_start: Starting scheduler on PRO CPU.
I (0) cpu_start: Starting scheduler on APP CPU.
I (356) test: Version: 0x00
I (356) ttn_hal: IO initialized
I (356) ttn_hal: SPI initialized
I (356) ttn_hal: Timer initialized
E (366) ttn_hal: LMIC failed and stopped: ../components/ttn-esp32/src/lmic/radio.c:1147

re-cheking the pinout now...

cc32d9 commented 4 years ago

very strange. This is the other library that works on exactly this hardware, and it's sending and receiving LoRa frames: https://github.com/Inteform/esp32-lora-library/blob/master/components/lora/lora.c

cc32d9 commented 4 years ago

ok it works now with your test: I added RST pin definition, and then this before sending a transaction:

    gpio_set_level((gpio_num_t)TTN_PIN_RST, 0);
    vTaskDelay(pdMS_TO_TICKS(1));
    gpio_set_level((gpio_num_t)TTN_PIN_RST, 1);
    vTaskDelay(pdMS_TO_TICKS(10));
cc32d9 commented 4 years ago

ok, made it work. For some reason, it didn't like level 2:

in radio.c:

    // manually reset radio
#ifdef CFG_sx1276_radio
    hal_pin_rst(0); // drive RST pin low
    hal_waitUntil(os_getTime()+ms2osticks(1)); // wait >100us
    hal_pin_rst(1); // configure RST pin floating!
#else
    hal_pin_rst(1); // drive RST pin high
#endif
    //hal_waitUntil(os_getTime()+ms2osticks(1)); // wait >100us
    //hal_pin_rst(2); // configure RST pin floating!
    hal_waitUntil(os_getTime()+ms2osticks(5)); // wait 5ms
manuelbl commented 4 years ago

I'm glad you got it working. The solution is quite surprising. I've never heard of a similar problem. Can you measure if there is a pull-down resistor on the RST line that would keep the RFM95 module in reset if the line is not driven?

It's most likely not possible to fix this in the ttn-esp32 library without breaking anything else and without modifying the underlying arduino-lmic code. You can probably fix it in hardware if you connect a pull-up resistor to the RST line.

cc32d9 commented 4 years ago

it can be a menuconfig option to drive the RST, so that it doesn't break any compatibility.

I'm running a battery test now, and will try adding a pull-down resistor afterwards.

cc32d9 commented 4 years ago

haha, hab gerade deinen Profil angeschaut. Wir sind rund um die Ecke.

cc32d9 commented 4 years ago

it worked with a pull-up resistor on RST pin (10kOhm toward +3.3v)

manuelbl commented 4 years ago

Have you been able to measure why the pin is pulled down in the first place?

On Fri, May 22, 2020 at 10:03 AM cc32d9 notifications@github.com wrote:

it worked with a pull-up resistor on RST pin (10kOhm toward +3.3v)

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/manuelbl/ttn-esp32/issues/23#issuecomment-632556871, or unsubscribe https://github.com/notifications/unsubscribe-auth/ACTSOHCXRGT62GTTA3XDLXDRSYWTLANCNFSM4NFNIYQA .

cc32d9 commented 4 years ago

with ohmmeter, there's infinity between RST and both GND and +3.3V. And there doesn't seem to be a resistor on the schematic.

I'm preparing a patch that makes the floating RST configurable from Kconfig.

manuelbl commented 4 years ago

A patch in the form of a pull request to be integrated into the official release? If so, try to modify hal_esp32.cpp instead of radio.c if possible. radio.c is frequently replaced with the latest version from https://github.com/mcci-catena/arduino-lmic.

cc32d9 commented 4 years ago

have a look if you like it: https://github.com/cc32d9/ttn-esp32/commit/e854a8643d36cc77afd3c1e83f0f84ecf7f27f09

but probably it makes sense to submit a patch to arduino-lmic.

cyberman54 commented 4 years ago

description of mcci lmic says that in practice rst can left unconnected. in mcci lmic it is possible to select by defining RST not_a_pin.

manuelbl commented 4 years ago

Looks good.

I would probably make two minor changes:

manuelbl commented 4 years ago

@cyberman54 Unfortunately, leaving it unconnected or in floating state didn't work in this case. For some reason, the RFM95 module is held in reset if the RST pin is not actively driven high. This setup is not supported by MCCI LMIC.

cc32d9 commented 4 years ago

I think it makes sense to propose a patch to LMIC library maintainers. I'll take care of it.

cc32d9 commented 4 years ago

see my latest comment at https://github.com/mcci-catena/arduino-lmic/issues/579

if it's specific to Wemos board, then it makes sense to keep the workaround within ttn-esp32 library, as this is a popular esp32 board.

manuelbl commented 4 years ago

Released as part of version 3.2.0.

Thanks for the PR