3 years, 5 months ago.

STM devices broken with upgraded mbed-os

<Edited original post as discovered I2C also stopped working> Anyone able to help figure a fix: upgrading to mbed-os 5.7.7 broke I2C (a very simple chip read) and also the 1820s using the Sissors library, still using OpenDrain

Same code base that was working with OS5.5, upgraded libXdot and to mbed-os 5.7.7 (aligns with libXdot build)

in https://os.mbed.com/users/Sissors/code/DS1820/rev/236eb8f8e73a/

it now detects lines pulled down in reset, then fails as Bit_A and B are 1

in search_ROM_routine

                Bit_A = onewire_bit_in(pin);
                Bit_B = onewire_bit_in(pin);
                if (Bit_A & Bit_B) {
                    descrepancy_marker = 0; // data read error, this should never happen
                    ROM_bit_index = 0xFF;

I see some historical community discussions that STM had some code that was fixed, so removed from this library and its related to switching speeds. But I believe this library should work (and it did with same hardware).

I confirmed the open drain version is set in the macro, i.e.

#define ONEWIRE_INIT(pin)   pin->output(); pin->mode(OpenDrain)

I wonder if there's some mbed-os config or similar at play. Not sure how to figure it out.

The I2C chip functions were returning -1. I didn't look too closely. As I wasn't sure what I've done wrong, I reverted to the old library and everything works again

Thanks for any suggestions

Why specifically Mbed OS 5.7.7? Have you tested Mbed OS 5.11.5?

posted by Zoltan Hudak 05 Mar 2019

Hi Zoltan. the Xdot stable build library was built with 5.7.7. There are (only) dev builds with newer mbed-os. "The Dot library version and the version of mbed-os it was compiled against can both be found in the commit message for that revision of the Dot library. Building your application with the same version of mbed-os as what was used to build the Dot library is highly recommended!"

posted by Brad S 05 Mar 2019

Sorry I didn't notice that you need also libXdot. Could you try https://os.mbed.com/users/hudakz/code/DS1820/? It's using open drain for STM MCUs too. If that works than it must be something else.

posted by Zoltan Hudak 05 Mar 2019

Thanks Zoltan. I fully expected to try that and have a problem ... but nope. your library added in to the same codebase with just some name tweaks to avoid 2 DS1820 classes returns a temperature, while the other hits that data read error.

Switching over DS1820 library would be an option, but as the I2C read is also failing. Any chance you can help me diagnose what is different in these libraries that would be affected by the updraded os / target / config?

posted by Brad S 07 Mar 2019

trying to look for answers. not sure what this is, other than odd. inline gpio_read() in the stm target return ((*obj->reg_in & obj->mask) ? 1 : 0);

onewire.h seems to be the opposite. #define READ() ((*gpio.reg_in & gpio.mask) != 0)

but both one-bit-in functions use answer=read() and there is no difference between the target files for this in newer and older STM targets

PS sorry, not sure how to format code in comments

posted by Brad S 07 Mar 2019

To read the one-wire line status, Sissors library adapted the same code as used by mbed library to read GPIO status, which is defined in mbed-os/targets/TARGET_STM/gpio_object.h

static inline int gpio_read(gpio_t *obj)
    return ((*obj->reg_in & obj->mask) ? 1 : 0); 

In my version of OneWire I tried to optimize that piece of code in hope to make it a bit shorter and faster.
Assuming that:

  • obj->reg_in is same as gpio.reg
  • obj->mask is same as gpio.mask
  • and that the ternary operator is actually equivalent to

if ((*obj->reg_in & obj->mask) != 0)
    return 1;
    return 0;

we can achieve the same goal if we simply write

return ((*gpio.reg_in & gpio.mask) != 0);

but probably with less binary code and hence faster.

So it must be something else. I'll try to have a closer look and let you know in case I find something.

PS: To format your code surround it with <<code>> and <</code>> tags, each on separate line:

your source code

posted by Zoltan Hudak 07 Mar 2019

ahh. thanks x2. of course... sorry. (not the first time I stuffed up a double negative (not false == is true)) I'm really not seeing anything 'obvious'. The only other avenue I'm even thinking possible within these libraries is the slight difference in delay times, so if the target timer code has changed, those delays cause this behaviour. But that seems 1) unlikely 2) not sure how/if it could cause these bits to both be high simultaneously In the back of my mind I'm trying to think of something further away - that may have changed to affect 1 wire and I2C , but 1 wire in only the other library??? I'm seriously stumped

posted by Brad S 08 Mar 2019

Ok I fixed I2C. STM modified the default correctly from pullup to nopull. pullup had obscured that our hardware guy missed a pullup resistor there. Still stuck on 1 wire

posted by Brad S 08 Mar 2019

Getting closer I think - I tested your library. if the 0xF0 byte doesn't get written, the error mode is what happens in sissors library. I realise its the other library but its not using the byte_out function, rather calling the equivalent loop on bits. I still can't see why the write may be failing with the updated mbed-os, target etc Edit written the same time as the accepted answer!

posted by Brad S 08 Mar 2019

1 Answer

3 years, 5 months ago.

I'm glad that you fixed the I2C bus. In case of one-wire the most critical is to meet the read time slot constrains.

  • First the GPIO shall be pulled down for at least 1us. That's easy to achieve by having the GPIO configured as ouput and writing a 0 to it.
  • Then the GPIO has to be reconfigured from output to input. To accomplish this as quickly as possible Sissors decided for STM targets to configure the GPIO as open drain.
  • But it is also important to finish the read operation (indicated as 'Master samples' in the picture above) within the correct time frame (about 13 us). In Scissors library for STM targets this is done as:

    #define ONEWIRE_DELAY_US(value) wait_us(value)

    ONEWIRE_DELAY_US(3);   // takes 3 us
    ONEWIRE_INPUT(pin);    // takes ? us (but certainly more than 1 us)
    ONEWIRE_DELAY_US(10);  // takes 10 us
    answer = pin->read();  // takes ? us

My suggestion is to remove ONEWIRE_DELAY_US(3) in first step and see how it works.

    ONEWIRE_INPUT(pin);    // takes ? us (but certainly more than 1 us)
    ONEWIRE_DELAY_US(10);  // takes 10 us
    answer = pin->read();  // takes ? us

If that doesn't help then try to reduce the delay one by one until it works.

    ONEWIRE_DELAY_US(9);  // takes 9 us

Accepted Answer

Zoltan. You are my hero. This fixed it. removed the 3us and 10us down to 8us seems to be working thanks so much

posted by Brad S 08 Mar 2019