DavidAntliff / esp32-ds18b20-example

ESP32-compatible example for Maxim Integrated DS18B20 Programmable Resolution 1-Wire Digital Thermometer.
MIT License
108 stars 34 forks source link

Multiple ds18b20 on different GPIOs instead of one #23

Closed christian-sigmaheat closed 2 years ago

christian-sigmaheat commented 2 years ago

Hey David,

thanks for your great work, very useful!

Wondering if it is also possible to use multiple (in my case 8) sensors on 8 different GPIOs. Seems like there are only 8 rmt channels in total (RMT_CHANNEL_0 ... _7) and two are needed for each OneWireBus (tx_channel and rx_channel), which would allow for only 4 GPIOs. Is that the case or did I misunderstand how to use the rmt channels?

Greetings Chris

DavidAntliff commented 2 years ago

@christian-sigmaheat thank you.

It's been a while since I've designed my own new projects with this library so I have to cast my mind back, but I think you're right - two RMT channels are used for each one-wire bus, limiting it to 4 busses.

Is there anything preventing you from using multiple DS18B20 devices on a fewer number of busses? Two per bus for example? Do you need precisely synchronised measurements across all 8 devices?

EDIT: just checked whether two RMT channels is necessary and reminded myself that yes, the directions of communications on the One-Wire bus are interleaved (rather than consecutive), so two channels are needed.

christian-sigmaheat commented 2 years ago

Thanks for chekcking!

Using less GPIOs than 8 is not an option in this case, as the hardware is already built in this specific way and can't be changed anymore.. It's not necessary though, to take measurements simultaneously.

Do you think it would be ok to to change the GPIO in the owb_rmt_driver_info after doing one measurement, uninitialize the "old" OneWireBus with [static owb_status _uninitialize(const OneWireBus *bus)] and re-initialize it to a new OneWireBus for the next GPIO and so on? Or if you have any other ideas, I'd apprecieate it very much!

DavidAntliff commented 2 years ago

Well, off the top of my head, if you were to use eight instances of my driver, then use a single pair of RMT channels with the ESP32's GPIO Matrix to switch the GPIO for each device, it might work, since each transaction is independent of the previous or next.

You need multiple instances of my driver since each instance expects to speak to a specific device (by device ID), but if you wrap it in some GPIO Matrix shenaningans in-between accesses then it could work...

Does that make sense? I don't have any example code for this unfortunately, but I know it is possible to change the RMT-to-GPIO mapping on-the-fly.

DavidAntliff commented 2 years ago

Sorry, didn't answer your question directly:

Do you think it would be ok to to change the GPIO in the owb_rmt_driver_info after doing one measurement, uninitialize the "old" OneWireBus with [static owb_status _uninitialize(const OneWireBus *bus)] and re-initialize it to a new OneWireBus for the next GPIO and so on?

Possibly - if you're not wanting to access it very fast (say, one measurement from a sensor per second) then this could work. Basically one-shot instances of the driver. Might churn a lot though. I think personally I'd go first for the Matrix idea above.

christian-sigmaheat commented 2 years ago

Hey, I managed to get it done somehow with the init/uninit-approach as I wasn't sure how to start with the multiplexing one, but at least it seems to work! Only thing I'm a little concerned about is if I may allocate too much memory over time, which might not be freed appropriately..

So one last question: I'm currently creating a OneWireBus with owb_rmt_initialize(...). Then I use ds18b20_malloc() to create a DS18B20_Info. Then ds18b20_init_solo() it and convert + ..._read_temp to do the measurement.

What's the correct way of undoing everything afterwards? I use owb_unititialize(OneWireBus) and could maybe use ds18b20_free(DS18B20_Info). But what about the ds18b20_init_solo(), is there any function to uninitialize it or how to go about that properly?

DavidAntliff commented 2 years ago

I've never run the code like this so I'm not able to provide any assurances that this will work, but from my quick review of the code it doesn't look like you need to do anything about ds18b20_init_solo() as it doesn't allocate any memory. The owb_uninitialize() and ds18b20_free() look to be sufficient to clean up allocated memory. There are ways to check free memory so you could print that out every few seconds to ensure you don't have a leak.

I do think the multiplexing way would be a better option in the long term, but I understand it may be tricky to get started. Maybe these links will help:

christian-sigmaheat commented 2 years ago

All right, works without memory leaks. Once again, thank you so much David for your fast and accurate help!