pstolarz / OneWireNg

Arduino 1-wire service library. OneWire compatible. Dallas thermometers support.
BSD 2-Clause "Simplified" License
86 stars 19 forks source link

More than 2 oneWireng istances #61

Closed mr-miky closed 11 months ago

mr-miky commented 11 months ago

I am using an RP2040 with arduino pico sdk (not MBED). The problem is that if I use oneWireNg (PIO version) I can’t instantiate more than 2 onewire connections. If I try to use more than 2 of them the RP2040 hangs even before entering setup().

in this way the RP2040 works

static OneWireNg_CurrentPlatform pippo(BEDROOM_PIN, false);
static OneWireNg_CurrentPlatform pluto(BATHROOM_PIN, false);
//static OneWireNg_CurrentPlatform topolino(LIVINGROOM_PIN, false);
//static OneWireNg_CurrentPlatform minnie(KITCHEN_PIN, false);

in this hangs

static OneWireNg_CurrentPlatform pippo(BEDROOM_PIN, false);
static OneWireNg_CurrentPlatform pluto(BATHROOM_PIN, false);
static OneWireNg_CurrentPlatform topolino(LIVINGROOM_PIN, false);
static OneWireNg_CurrentPlatform minnie(KITCHEN_PIN, false);

I also tried to use the bitbanging mode and in this mode I can instantiate 4 connections but then it hangs when I try to reset the 1-wire bus. This last problem is also present in OneWire not ng and is caused by the use of noInterrupts() and interrupts() before and after delayUs().

The only way I can use the bitbanging version is to comment out noInterrupt() and interrupts() in Platform_Time_Critical.h

#elif defined(ARDUINO)
# define timeCriticalEnter() //noInterrupts()
# define timeCriticalExit() //interrupts()

Also in the old version of oneWire, if I want it to work, I have to comment out most of the noInterrupts() and interrupts().

pstolarz commented 11 months ago

PIO driver

You may create up to 8 different OneWireNg objects derived from OneWireNg_PicoRP2040PIO driver. To do this you need:

...

// create SMs for 1st PIO for 4 distinct pins ow1 = new OneWireNg_PicoRP2040PIO(SOME_PIN1, PULLUP_CONF, 0); ow2 = new OneWireNg_PicoRP2040PIO(SOME_PIN2, PULLUP_CONF, ow1); ow3 = new OneWireNg_PicoRP2040PIO(SOME_PIN3, PULLUP_CONF, ow1); ow4 = new OneWireNg_PicoRP2040PIO(SOME_PIN4, PULLUP_CONF, *ow1);

// create SMs for 2nd PIO for 4 distinct pins ow5 = new OneWireNg_PicoRP2040PIO(SOME_PIN5, PULLUP_CONF, 1); ow6 = new OneWireNg_PicoRP2040PIO(SOME_PIN6, PULLUP_CONF, ow5); ow7 = new OneWireNg_PicoRP2040PIO(SOME_PIN7, PULLUP_CONF, ow5); ow8 = new OneWireNg_PicoRP2040PIO(SOME_PIN8, PULLUP_CONF, *ow5);



NOTE 1: I don't recommend to create `OneWireNg` objects on the static level, since these objects are created at the very initial stage of the program execution and may not always work as you expected. Allocate them using `new` operator by dynamic or in-place memory allocation (see the README for details).

NOTE 2: In this example I'm using directly specified driver `OneWireNg_PicoRP2040PIO` not `OneWireNg_CurrentPlatform`, since the constructors used here are PIO specific.

NOTE 3: If `CONFIG_RP2040_PIOSM_NUM_USED` is set to `2` (the default value) you may create only 2 SMs per PIO, so 4 SMs max. I've observed some minor timings issues if `CONFIG_RP2040_PIOSM_NUM_USED` is `1`, but I believe it shouldn't be an issue for you. Set `1` and give it a try.

**Bit-banging driver**

I don't see a reason for the limit of `OneWireNg` objects created in this case. Make sure to call these objects in a serial order (1st, next 2nd, next 3rd and so on) ~or use mutexes  to assure serialization if you call them in threads. `interrupts()` is not re-entrant and it's the reason of problems I guess.~

BTW: You may try to play with `CONFIG_BITBANG_TIMING` param in `OneWireNg_Config.h` and set it to `TIMING_RELAXED` or even `TIMING_NULL` and check results.

EDIT: I've just checked bit-banging driver working on 6 different pins 13-18 for 6 `OneWireNg` objects. No issues observed.

EDIT 2: The re-entrance in multi-threads environment shouldn't be the issue neither. You don't need to use mutexes for this case, since by blocking interrupts threads scheduling will be effectively disabled for a single core and `interrupt()` re-entrance will not occur.
mr-miky commented 11 months ago

no way...


static OneWireNg_PicoRP2040PIO *homeWires[] = {nullptr, nullptr, nullptr, nullptr};

...

void setupOneWire() {

    homeWires[KITCHEN] = new OneWireNg_PicoRP2040PIO(KITCHEN_PIN, false, 0);
    homeWires[BEDROOM] = new OneWireNg_PicoRP2040PIO(BEDROOM_PIN, false, *homeWires[KITCHEN]);
    homeWires[LIVINGROOM] = new OneWireNg_PicoRP2040PIO(LIVINGROOM_PIN, false, *homeWires[KITCHEN]);
    homeWires[BATHROOM] = new OneWireNg_PicoRP2040PIO(BATHROOM_PIN, false, *homeWires[KITCHEN]);

}
void findDevs() {

    OneWireNg::Id id;
    OneWireNg::Id tempSensor[4] = { };

    for (uint8_t i = 0; i < 4; i++) {

        if (homeWires[i] != nullptr) {

            Sprint("Searching for DS18S20 on bus : %d\n", i);

            homeWires[i]->searchFilterAdd(DS18S20);
            homeWires[i]->searchFilterAdd(DS2408);
            homeWires[i]->searchReset();

            while (homeWires[i]->search(id) == OneWireNg::EC_MORE) {
                if (*tempSensor[i] != DS18S20)
                    memcpy(&tempSensor[i], &id[0], sizeof(OneWireNg::Id));

                printId(id);
                Serial.println("----------");
            }
        }
        else
            Sprint("Uninitialized bus %d\n", i);
    }
}
void setup() {

    Serial.begin(115200);

    while (!Serial) {
        delay(100);
    }

    pinMode(LED_BUILTIN, OUTPUT);

...

    setupOneWire();

    findDevs();

    wait = millis();
}

Nothing has changed at all.

In setup() when I run setupOneWire(); hangs and does not run findDevs();

The only way to make it run findDevs(); and then loop(); is to limit it to 2 new OneWireNg_PicoRP2040PIO(......

void setupOneWire() {

    homeWires[KITCHEN] = new OneWireNg_PicoRP2040PIO(KITCHEN_PIN, false, 0);
//  homeWires[BEDROOM] = new OneWireNg_PicoRP2040PIO(BEDROOM_PIN, false, *homeWires[KITCHEN]);
    homeWires[LIVINGROOM] = new OneWireNg_PicoRP2040PIO(LIVINGROOM_PIN, false, *homeWires[KITCHEN]);
//  homeWires[BATHROOM] = new OneWireNg_PicoRP2040PIO(BATHROOM_PIN, false, *homeWires[KITCHEN]);

}

and result is :

Searching for DS18S20 on bus : 0
Uninitialized bus 1
Searching for DS18S20 on bus : 2
10:36:A3:6E:0:8:0:2A
----------
10:6E:BC:6E:0:8:0:B6
----------
10:1E:A2:48:0:8:0:89
----------
10:D5:80:6E:0:8:0:EC
----------
Uninitialized bus 3

N.B. KITCHEN aka bus 0 is disconnected...

mr-miky commented 11 months ago

oh noooo i forgot to change -DCONFIG_RP2040_PIOSM_NUM_USED=2 in the compile command

I must absolutely go to sleep !

pstolarz commented 11 months ago

With the above usage you MUST set CONFIG_RP2040_PIOSM_NUM_USED to 1 since you are using 4 SMs on the same PIO.

mr-miky commented 11 months ago

oh noooo i forgot to change -DCONFIG_RP2040_PIOSM_NUM_USED=2 in the compile command

I meant I forgot to change it to 1 , it had always been set to 2 in all tests :-(

pstolarz commented 11 months ago

Ok, so I assume it's working now.

mr-miky commented 11 months ago

PIO mode now seems to work with short links, tomorrow I try with 20m links.

What puzzles me is the Bit-Banging mode and the noInterrupts()/interrupts() issue. Tomorrow if I have time I investigate with the debugger to understand why delayUs() enters coma to the third sequence of

noInterrupts(); delayUs(xxx); interrupts();

for example in the reset() function of the old oneWire library. NB. the same code compiled for STM32 and atmega328p is no problem