OneWire thermometer DS18B20

Porting OneWire to Arduino STM32

posted in: Arduino | 0

Onewire devices are commonly used with the Arduino, including the excellent DS18x20 thermometer.

Unfortunately the OneWire library accesses the micro-controller GPIO hardware directly. This appears to be in order to meet the bus timings when using 16Mhz AVR devices.

The OneWire library has already been ported to Arduino Due as well as Teensy and PIC32, and has a defined way to add new architecture by adding a new block of code into OneWire.h to implement various library specific macros.

So initially it looked like the same approach of adding a new section, with appropriate #ifdef’s, would be all that was required.

However it quickly became apparent that the method used to support different architectures, by storing a bitmask of the pin to be controlled and a “base register” for the GPIO hardware, was not compatible with the STM32 GPIO access:

Firstly, the STM32 GPIO port control register, which sets the mode of the pins, e.g. Input or Output (and many other options), is split into two 32bit registers not one control register as on the AVR and other hardware supported by the OneWire library.

Secondly, the method to set and reset individual bits, using a bitmask, by reading the Output register, and’ing or or’ing and then writing back – is not the best method to do this on STM32 dices

STM32 have a Set/Reset register ( BSSR ), where the upper 16 bits control the resetting of bits and the lower 16 bits control the setting of bits within the port. Single write to the BSSR can set or rest a bit as required, and hence is much faster, than reading, or’ing / and’ing and writing back.

So the combination of bitmask being a slower way to set, and reset bits, accompanied by the STM32 code needing to determine which of the two control registers to use, meant that there was no way to use the bitmask and base register variables in the library as they had initially been intended.

The only approach that worked without changing the c code, was to use the bitmask variable to store the “pin number” and for the macro’s to ignore the base register variable, and to look-up the GPIO port data structure via the PIN_MAP array, which gives both the base address of the port in question and also the bit number within the port.

This did make the macro’s considerably more verbose than on all other architectures, and made them slower than comparable hardware like the PIC32 and the Teensy, but there was no other option whist still attempting to add the STM32 support within the prescribed method of supporting new hardware, in OneWire.h.

I tested the code using a DS18B20 thermometer, and the library worked fine, so I committed it to the repo.


At this point I was contacted by Bill Perry on the Arduino forum, to let me know that actually the OneWire protocol is relatively slow, and all this messing around with direct hardware access is really only necessary on 16Mhz AVR devices, and that any processors which are significantly faster, like the 72Mhz STM32F103’s could easily fulfill the bus timings using the normal cross platform Arduino API calls of pinMode(), digitalWrite() and digitalRead().

As a sidenote. In my initial testing, I had tried using the API calls and noted that they appeared to work, but I presumed that there must be a reason that direct hardware access was being used on the PIC32 and the Teensy which are both very fast device, and hence I carried on trying to use write macros to be as fast as possible.

But with Bill’s input, I did some more timing tests using the API calls and verified using an oscilloscope that the STM32 was definitely fulfilling the bus timing specifications.

Using API call’s opened a window of opportunity to get the master copy of OneWire updated, to include  generic / fallback support for all other architectures, as no non-standard / repo specific functions would need to be added to the OneWire header, and it would probably allow a number of other existing architectures, e.g. TiLaunchPad,  to have OneWire support without requiring their own specific implementations of OneWire


I emailed

Unfortunately at the time of writing this post, after 1 week, I have not received any acknowledgement to my pull request whatsoever from Paul, which I find somewhat disappointing.

In the mean time, I have added the modified copy of the library, which uses API calls to the libraries folder for the STM32F1 device. But hopefully in the longer term this can be removed when and if the changes are accepted by Paul.