-
Notifications
You must be signed in to change notification settings - Fork 33
reduce library size by 2036 bytes of flash (~50%) and 157 bytes of ram (~73%) #32
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
…es of flash and 14 bytes of ram
…04 bytes of flash and 30 bytes of ram
…h and 113 bytes of ram
For me it's ok, |
Sounds good to me. As I said in #28, as the TwoWire class does not have virtual methods, deriving from it is totally pointless. I would have preferred "the other solution" (i.e.: Making the methods virtual in the parent class), but since that is not going to happen, the only other meaningful thing to do is this one, as we are currently wasting flash and RAM for no useful purpose.
|
It sounds good, but I need to test it with the hd44780 library to make sure it actually works as expected. |
The TwoWire and Wire.h were used to be compatible with other libraries that use them. As a result a unused "Wire" object is sitting in memory. This is related to: #28 were @bperrybap already wrote about it. The goal is to be able to use both Wire (hardware I2C bus) with multiple SoftwareWire ojects in the same sketch and be compatible with all the sensor libraries. Most libraries use pointers to TwoWire, others might use a template. I have even seen The virtual destructor is a bug. Changing the other things will result into trouble in one way or the other in my opinion. |
The patch appears to revert code back to the 1.5.0 release with a few minor changes.
I'm not sure the purpose of that last change, particularly the altering of the handling of SDA (setting it low) @Koepel
While I think that compatibility goal is desirable, I don't think it is technically possible to do what you have sated. Also, I don't think it is possible to have both Wire and Software library classes use the class name "TwoWire" to allow libraries to work that use pointers to TwoWire and be able to use both libraries simultaneously in the same sketch. I think the only way a library can guarantee to be compatible with various i2c libraries is to use a template with pointers so that it no longer cares about the object name or its class. Currently, the hd44780 library does not use templates yet to handle the i2c class and object. It currently depends on the sketch to include that proper i2c library header and then ensure that a Wire object exists. |
Let me rephrase that: Most libraries that try to be able to select a Wire library use a pointer to a TwoWire object. Personally, I like templates make the library compatible at source code level, but the TwoWire pointer way has also some advantages if it is consistently used. You see problems with both a hardware and one or more software I2C buses in the same sketch ? That would be disappointing. |
Yes I definitely agree with that. Maybe I misunderstood you. I took that to mean being able to use objects from both Wire and Software at the same time (multiple i2c buses) and using TwoWire as the name of the class for both. i.e. in the absence of having a wrapper class named TwoWire provided by the bundled IDE i2c library you can either have the TwoWire class name used by all the i2c libraries (like this this one) and provide a global predefined object named Wire, which provides great compatibility with the Arduino.cc bundled Wire library but also prevents using more than one i2c library at a time Or you can have unique class names for each i2c library which allows concurrent use but will not be compatible with libraries that hard code the class name to TwoWire or use a hard coded wire object name like Wire. So I guess I still don't understand what you mean by: Are you pushing for making SoftwareWire fully compatible with the Wire library (which means you can't use the Wire library when using the SoftwareWire library) or something else that allows using both at the same time? BTW, this same issue exists in other libraries like Arduino libraries that sit on top of libraries for hd44780 displays. The only solution that I have seen that works for all cases (multiple objects for using multiple buses including using multiple libraries using different class names) is to use templates where the user passes in the class to the template when the object is declared. |
Adafruit may use a If the alternative proposal is that I do think it is beneficial for the |
Thanks for the explanation. Suppose someone has a sensor with a library with a TwoWire pointer for the hardware I2C bus and wants to add a software I2C bus with a sensor library that also uses a TwoWire pointer. I understand now that it is not possible. If someone wants something extraordinary, then we have to tell to change the sensor library. |
So we're all finally in agreement? I will merge this PR and publish a V1.5.2 to the library manager thank you all |
Agreed, but I'd rather make that 1.6.0. And maybe you can also check that all method signatures match TwoWire's and close #27 as well. |
@SukkoPera: |
Added this page to the Wiki: Using a library that needs a TwoWire pointer |
@Koepel: That's good information. I have another way of doing this, but it's not quite ready for public consumption. I'll add some info on that wiki when it's ready. I recently evaluated many of the libraries listed in this wiki page, https://github.com/Testato/SoftwareWire/wiki/Arduino-I2C-libraries. I added a few entries, added some comments, and refactored the page a bit. The biggest change is that I grouped the libraries according to their target architecture. |
FYI: I did another substantial update to the Arduino-I2C-libraries wiki page. Three big changes:
|
According to my testing, this library currently consumes about 3926 bytes of flash and 216 bytes of static ram on an Arduino Nano (after subtracting away an empty program that does nothing, i.e. empty
setup()
and emptyloop()
). This PR reduces the flash consumption by 2036 bytes, and ram consumption by 157 bytes, through the following steps:1)) Remove virtual on destructor. Saves 592 bytes of flash and 14 bytes of ram by preventing the virtual destructor from pulling in
malloc()
andfree()
. Making the destructorvirtual
has no benefit for theSoftwareWire
class as far as I can see, because neither of its parent classes (TwoWire
andStream
) defines a virtual destructor. That means thatSoftwareWire
cannot be deleted polymorphically. In other words, in the following code:the
delete
operator calls~TwoWire()
, not~SoftwareWire()
. I have actually tested this, and verified that "wrong" destructor (~TwoWire()
) is called. (It is the correct destructor as far as the C++ language spec is concerned, just not the one that we wanted). When the above code is compiled with warnings enabled, the compiler prints the following warning:which is an additional indication that making the destructor
virtual
does not have the desired effect.2)) Remove inheritance from TwoWire. Saves 304 bytes of flash and 30 bytes of ram. The PR that attempted to make
TwoWire
polymorphic (arduino/ArduinoCore-avr#396) was reverted (arduino/ArduinoCore-avr#412) because it causesTwoWire
to increase its flash memory by about 650 bytes. I think it is safe to assume thatTwoWire
will not support subclassing in the future. So we can save memory by changingSoftwareWire
to no longer inherit fromTwoWire
.3)) Remove including Wire.h. Saves 1140 bytes of flash and 113 bytes of ram. Just the inclusion of the TwoWire header file (through
#include <Wire.h>
) causes over 1kB of flash to be consumed, even if theWire
object is never used. For reasons which are not obvious to me, the compiler is unable to determine thatWire
is never used in the program, and does not optimize it away during link time. Since (2) above changesSoftwareWire
so that it is no longer a subclass ofTwoWire
, we no longer need to include<Wire.h>
.Total flash savings: 2036 bytes, from 3926 bytes down to 1890 bytes
Total ram savings: 157 bytes, from 216 bytes down to 59 bytes
This PR causes the following effects:
For people who are interesting in using this patch, I will probably keep around my fork (https://github.com/bxparks/SoftwareWire) while this PR remains unmerged.