0

I'm studying the structures of libraries currently. I want to learn how good programmers write code, what are the strategies they follow, the art the programmer followed to develop the library. And how important the library should be written in the well arranged form.

But as I'm go back and forth into the library over and over, I really need to understand, the way the programmer followed, and the reasons behind the applied strategy.

The example I'm studying now is the HMC5883L and how the programmer used the Wire library to manage the developing the library. This should be quite easy for experienced programmers, but I'm really studying the concepts, strategies .. etc.

As I'm going over and over I have different questions, so to start this discussion I want to begin with this question about the programmer writing two very similar functions that pretty much do the same thing.

// Read byte to register
uint8_t HMC5883L::fastRegister8(uint8_t reg)
{
    uint8_t value;
    Wire.beginTransmission(HMC5883L_ADDRESS);
    #if ARDUINO >= 100
        Wire.write(reg);
    #else
        Wire.send(reg);
    #endif
    Wire.endTransmission();

    Wire.requestFrom(HMC5883L_ADDRESS, 1);
    #if ARDUINO >= 100
        value = Wire.read();
    #else
        value = Wire.receive();
    #endif
    Wire.endTransmission();

    return value;
}

// Read byte from register
uint8_t HMC5883L::readRegister8(uint8_t reg)
{
    uint8_t value;
    Wire.beginTransmission(HMC5883L_ADDRESS);
    #if ARDUINO >= 100
        Wire.write(reg);
    #else
        Wire.send(reg);
    #endif
    Wire.endTransmission();

    Wire.beginTransmission(HMC5883L_ADDRESS);
    Wire.requestFrom(HMC5883L_ADDRESS, 1);
    while(!Wire.available()) {};
    #if ARDUINO >= 100
        value = Wire.read();
    #else
        value = Wire.receive();
    #endif
    Wire.endTransmission();

    return value;
}

Update: Actually, the programmer used the 1st version only in the HMC5883L.begin(); function, but why?

if ((fastRegister8(HMC5883L_REG_IDENT_A) != 0x48)
|| (fastRegister8(HMC5883L_REG_IDENT_B) != 0x34)
|| (fastRegister8(HMC5883L_REG_IDENT_C) != 0x33))
{
return false;
}

Everything else in the library used the 2nd version.

So, basically the two functions are to read a specified register in the HMC5883L, my questions:

  1. what is the difference? I know that there's an extra care has been put into the second function, but why ?
  2. Is it so important ?
  3. Are there situations that require any version of the functions ?
2
  • There has never been a "fast" way to do i2c, it is a myth. There are many wrong ways to do i2c.
    – Jot
    Commented Apr 27, 2019 at 12:57
  • Yes, I'm still learning how i2c is actually working, and to deal with i2c chips.
    – R1S8K
    Commented Apr 27, 2019 at 19:42

2 Answers 2

2

TBH the second version of the function is trash. The first version is (almost) the right way to do it. There's stuff in the second version that really shouldn't be there. There is absolutely no reason why the creator of the library created that second function.

  • It "waits" for data to be available, when that data will be available the moment requestFrom() completes - so is completely redundant
  • It makes a spurious beginTransmission() call right before the requestFrom() call. beginTransmission() is only for writing, not for reading. It's pointless there.

However:

  • Both functions do an endTransmission() after the receiveFrom(), which makes no sense - the endTransmission() goes to balance a beginTransmission() only - not a receiveFrom(). receiveFrom() is a completely self-contained function that needs no other handling.

This library is probably not a good one to study for learning how to use the Wire library. It contains code that indicates the author themselves didn't have a proper grasp of the workings of the library.

9
  • Thank you so much dude ! I mean you ARE the man seriously :) I'm really happy that my points of question are considerable and important. I would try to develop my library too, it's for me about grasping more and more skills, information and how to learn the art of programming. I need to forget about my old codes and libraries :)
    – R1S8K
    Commented Apr 27, 2019 at 11:44
  • But if I got some more questions, should I get back here. Or remove the choose the answer until I finish discussion on the topic?
    – R1S8K
    Commented Apr 27, 2019 at 11:46
  • If you have new questions, then ask new questions. Keep it "atomic" :)
    – Majenko
    Commented Apr 27, 2019 at 11:46
  • all HMC5883L libraries for Arduino have it like this :-) (including Adafruit)
    – Juraj
    Commented Apr 27, 2019 at 12:05
  • They all copied off each other then :) I have a DTWI one for chipKIT that doesn't do it that way - but then DTWI doesn't work the same as Wire...
    – Majenko
    Commented Apr 27, 2019 at 12:14
1

There is no "fast" way to do i2c. If you already use the "fast" functions in your code, then you can make it a inline call to readRegister8.

The function below reads a byte from the HMC5883L.
When the HMC5883L is not connected, the Wire.read() returns -1. That will be converted to a return value of 0xFF.

// Read byte from register
uint8_t HMC5883L::readRegister8(uint8_t reg)
{
    uint8_t value;
    Wire.beginTransmission(HMC5883L_ADDRESS);
    Wire.write(reg);
    Wire.endTransmission();    // add parameter 'false' for repeated start

    Wire.requestFrom(HMC5883L_ADDRESS, 1);
    value = Wire.read();

    return value;
}
4
  • But doesn't it need Wire.endTransmission(); after value = Wire.read();?
    – R1S8K
    Commented Apr 27, 2019 at 18:17
  • No, never, only when writing data. See: arduino.cc/en/Reference/WireEndTransmission It is one of the bugs in the code that Majenko mentioned in his answer.
    – Jot
    Commented Apr 27, 2019 at 20:05
  • OK, I'm moving around the i2c area, done some work with the Wire library and tested some lines about reading each register. Next, I should do a similar robust i2c code that is working with similar management of data in the ISR and locking each mode until it's ready.
    – R1S8K
    Commented Apr 27, 2019 at 20:14
  • Yep, you're right, I should put false between the write / read operations. Found this one the link: If true, endTransmission() sends a stop message after transmission, releasing the I2C bus. If false, endTransmission() sends a restart message after transmission
    – R1S8K
    Commented Apr 27, 2019 at 20:17

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.