EnviroDIY / Arduino-SDI-12

An Arduino library for SDI-12 communication with a wide variety of environmental sensors. This library provides a general software solution, without requiring any additional hardware.
https://github.com/EnviroDIY/Arduino-SDI-12/wiki
BSD 3-Clause "New" or "Revised" License
161 stars 100 forks source link

Examples Will Now Compile For Arduino R4 But Still No Communication To/From SDI-12 Sensor #145

Open electromechpro opened 3 weeks ago

electromechpro commented 3 weeks ago

Thank you for the work last week with micros() on trying to get the Renesas platform 48 MHz Arduino R4 boards to run the SDI-12 library. When we updated the SDI12 library, the examples would compile for an Arduino R4, but we could not get it to send or receive data to/from an EnviroPro EP100G moisture probe. The earlier R3 Arduinos will communicate ok.

I do not know what the cause is, but here are some observations we made:

1: The resolution of micros does not appear to be 1 microsecond for the 48 MHz R4.

2: The "TICKS_PER_BIT 833UL" line looks different from the other ticks per bit lines that have just a number after "BIT ".

3: Around line 205 in SDI12_boards.h, for the case "F_CPU >= 48000000L", that does not have "PRESCALE_IN_USE_STR" with some kind of string after it.

I hope the above are helpful. We would really like to upgrade the R3 UNOs to R4s and have more functionality. I can imagine it would not be possible to test if the library works with an UNO R4 without having one on hand. Can I help by testing out some code ideas with the R4 boards we have here and carefully describing any errors we get? I regret I do not have the knowledge to adapt the library myself, but would be glad to assist you.

SRGDamia1 commented 3 weeks ago

I'm sorry; I threw in the allowance to use the library down to 48MHz without any testing. The only boards I tested using the micros() math were faster ESP8266 and ESP32 modules.

2: The UL in the TICKS_PER_BIT 833UL means "this number is an unsigned long" (ie, uint32_t instead of uint8_t or uint16_t).

3: The library does not use the PRESCALE_IN_USE_STR macro, I put it there just for testing so I could print it out in my sketches for debugging.

  1. The resolution of micros() doesn't need to be 1µs. A single bit is 833.3 (!!) µs long. If the resolution is several microseconds, but the value is accurate the calculations should work. There would still be 833 ticks of the 1µs clock within each bit, even if you can't hear each tick. That's what the fudge factor is for - to force the calculation to round the time up because even at 1µs resolution 1/3 of the bits will be recorded as having 834 bits. An UnoR3 with a 328p chip at 16MHz uses a 1024x prescaler slowing the effective tick resolution to 64µs between ticks. But a 16MHz 328p works fine with this library. I think the problem with using micros() on a slower processor is that the total amount of time in the ISR is too long and the micros() function is also dependent on an ISR and they conflict and it goes down the tubes. The micros value isn't accurate enough. I work around it by using raw processor clock values and manually selecting prescalers.

Some things you can try to get it to work:

electromechpro commented 2 weeks ago

O-Scope

SDI-12 And The Arduino R4 8/26/24

Thank you for the helpful suggestions. In order of what we have tried here, our results follow:

• Try creative wiring to split the SDI-12 data line to connect to 3 wires: the Tx and Rx of a hardware serial port (ie, Serial1) and a pin to set the low and high levels for the break and the marking. You'd have to write the timing out for the break and marking, but hardware serial on your core probably supports 7E1 and 1200 baud. I've never tried this method. This seemed an awful kludge, but worth considering. We researched the circuit, using 2 diodes and a pullup resistor on the RX line. The R4 will support 1200,7E1 on the hardware serial port, but while I was fiddling with the hardware, my associate was working on the next suggestion: O Go back to version 1.1.0, which didn't use timers. The Rx ISR for this version waits for an entire character in each interrupt. There's also no CRC or parity checking. Modify the code to assign the interrupt function to the data pin and remove everything AVR-specific.

-The version 1.0 code also compiled for the R4, as there were no conditions that would not allow it. There were no AVR specific lines we had to remove. At first, we were unable to get the R4 to communicate with our EnviroPro moisture probe. We then hooked up an Oscope to the data line, broke out the SDI-12 spec sheet, and were able to see the Break and Mark signals, along with the data pulses coming from the Arduino. The sensor was not responding with any data. The Arduino R3 we had as a control was able to communicate (Serial console showed responses, as well as Oscope pulses). In both cases, the Mark and Break signals were within the specifications. Closer examination of the data pulses, however, (see picture) revealed that the R4 pulses were 900 microseconds, where the R3’s were 840. It seemed counterintuitive that an 8 bit, 16 MHz MCU would execute code faster than a 32 bit 48 MHz one, but we were able to get it to work by modifying the bit spacing constant in SDI12.cpp line 149

define SPACING 830 // 0.8 bit timing in microseconds (1200 baud = 1200 bits/second ~ 830 µs/bit)

From 830 to 800.

This was encouraging, and lead us to try the first suggestion: • Fiddle with the fudge factor (RX_WINDOW_FUDGE). Try bigger values, or smaller ones. See if you can get anything to work. I'm not hopeful. Some trial and error landed us on a factor of 95 from the original 50. While not fully aware of how it works, we can say that it does work, as we were able to get meaningful responses from both the moisture probe and our Campbell Scientific weather station.