The version of Wire that is currently used, is software / “big banged”, and doesn’t use the hardware I2C features of the STM32
The advantage of a software approach is that Wire can be run on any GPIO pins on the board (that are not used for other specific purposes e.g. Hardware serial)
The disadvantage is the speed. The default speed is 250kbps, and the fastest that can be achieved by minor changes to the Wire library somewhere under 400kbps. With direct GPIO access the speed could easily be increased beyond 400kbps, however at the moment, no one has requested this , or looked into speeding up Wire.
Only one change was required to the original Wire version (written by LeafLabs), which was to fix an issue where it would not work with the I2C scanner
example sketch.
PS.
I’m not absolutely sure why LeafLabs (who wrote all the original code, for their Maple products), chose to go with a software solution, (someone may be able to give us a definitive answer), but my understanding was that programming for the Hardware I2C is problematic, and there may even be bugs in the STM32 chips themselves with the hardware I2C features. The hardware errors are documented by STM, along with work arounds in a document that can be downloaded from their site.
The software mode (standard!) is definitely strange written: All commands use “digitalWrite” instead of direct pin manipulation, so this is for sure one reason, why there is no more speed beyond 250kbps.
I have included into my port of the adafruit OLED library “hardwire” as standard and see no issues with it. (super clean 400khz SCL with osci/logic analyzer, both (I2C1, I2C2) tested )
So keep in mind, using the SW “wire.h” version will slow down your code and I don’t know how it will react within time critical stuff or many used timers.
So my suggestions is (if you can use the I2c HW pins) to give hardwire a try before implementing this cheesy SW version.
Thanks.
I’ve never tried HardWire
One thing we could do relatively easily is update the software I2C to use direct register access, it will speed it up greatly and also still allow the flexibility of using whichever pins you want.
I recall several people on the Arduino forum saying they prefer an implementation that isn’t tided to specific pins.
But its good to have both options if they both work well.
Coding the GPIO stuff is not hard, but I’m not sure I have time to look at it at the moment
<…>
I’ve never tried HardWire
It Looks like the forum can be modified to open links into new tabs or windows, but it doesnt seem just to be a settings change,
https://www.phpbb.com/support/docs/en/ … w-windows/
PS. The site is using PHPBB. I tried MyBB but it didnt seem to have all the feature that would be needed, so chose PHPBB instead – as its an old stalwart
// --------------------------------------
// i2c_scanner
//
// Version 1
// This program (or code that looks like it)
// can be found in many places.
// For example on the Arduino.cc forum.
// The original author is not know.
// Version 2, Juni 2012, Using Arduino 1.0.1
// Adapted to be as simple as possible by Arduino.cc user Krodal
// Version 3, Feb 26 2013
// V3 by louarnold
// Version 4, March 3, 2013, Using Arduino 1.0.3
// by Arduino.cc user Krodal.
// Changes by louarnold removed.
// Scanning addresses changed from 0...127 to 1...119,
// according to the i2c scanner by Nick Gammon
// http://www.gammon.com.au/forum/?id=10896
// Version 5, March 28, 2013
// As version 4, but address scans now to 127.
// A sensor seems to use address 120.
//
//
// This sketch tests the standard 7-bit addresses
// Devices with higher bit address might not be seen properly.
//
#include <Wire.h>
void setup()
{
Wire.begin();
Serial.begin(9600);
Serial.println("\nI2C Scanner");
}
void loop()
{
byte error, address;
int nDevices;
Serial.println("Scanning...");
nDevices = 0;
for(address = 1; address < 127; address++ )
{
// The i2c_scanner uses the return value of
// the Write.endTransmisstion to see if
// a device did acknowledge to the address.
Wire.beginTransmission(address);
error = Wire.endTransmission();
if (error == 0)
{
Serial.print("I2C device found at address 0x");
if (address<16)
Serial.print("0");
Serial.print(address,HEX);
Serial.println(" !");
nDevices++;
}
else if (error==4)
{
Serial.print("Unknow error at address 0x");
if (address<16)
Serial.print("0");
Serial.println(address,HEX);
}
}
if (nDevices == 0)
Serial.println("No I2C devices found\n");
else
Serial.println("done\n");
delay(5000); // wait 5 seconds for next scan
}
// --------------------------------------
// i2c_scanner
//
// Version 1
// This program (or code that looks like it)
// can be found in many places.
// For example on the Arduino.cc forum.
// The original author is not know.
// Version 2, Juni 2012, Using Arduino 1.0.1
// Adapted to be as simple as possible by Arduino.cc user Krodal
// Version 3, Feb 26 2013
// V3 by louarnold
// Version 4, March 3, 2013, Using Arduino 1.0.3
// by Arduino.cc user Krodal.
// Changes by louarnold removed.
// Scanning addresses changed from 0...127 to 1...119,
// according to the i2c scanner by Nick Gammon
// http://www.gammon.com.au/forum/?id=10896
// Version 5, March 28, 2013
// As version 4, but address scans now to 127.
// A sensor seems to use address 120.
//
//
// This sketch tests the standard 7-bit addresses
// Devices with higher bit address might not be seen properly.
//
#include <Wire.h>
void setup()
{
Wire.begin();
Serial.begin(9600);
Serial.println("\nI2C Scanner");
}
void loop()
{
byte error, address;
int nDevices;
Serial.println("Scanning...");
nDevices = 0;
for(address = 1; address < 127; address++ )
{
// The i2c_scanner uses the return value of
// the Write.endTransmisstion to see if
// a device did acknowledge to the address.
Wire.beginTransmission(address);
error = Wire.endTransmission();
if (error == 0)
{
Serial.print("I2C device found at address 0x");
if (address<16)
Serial.print("0");
Serial.print(address,HEX);
Serial.println(" !");
nDevices++;
}
else if (error==4)
{
Serial.print("Unknow error at address 0x");
if (address<16)
Serial.print("0");
Serial.println(address,HEX);
}
}
if (nDevices == 0)
Serial.println("No I2C devices found\n");
else
Serial.println("done\n");
delay(5000); // wait 5 seconds for next scan
}
It’s possible some recent changes have broken something.
I will test and get back to you
~Straw
I tested with MPU9150 imu and BMP085 barometer and also with some I2C memory
The default bus speed may be too high, I think its around 250kbps, but Arduino is normally 100kpbs, perhaps I better change the default to normal Arduino speed.
Note. I could not get I2C to work with an OV7670 camera at 250kpbs I had to instantiate another instance of Wire and run at 100kpbs
But the other issue with the OV7670 is its not technically I2C, its SCCB.
They are basically the same protocol, but in practice the implementation in the OV7670 doesn’t appear to work with a lot of I2C hosts.
Hence a lot of people end up writing GPIO bit banged implementations of I2C variants for use with this device.
Luckily Wire in libmaple is bit banged and works with SCCB but only at low speeds.
And as its only a control bus to setup the camera, its not worth messing around to get the speed any higher
I think the OV7670 module I have, has 4.7 on the board (I didnt check their precise value)
The OV7670 spec is SCCB to 400khz, and I2C is defaulted to 250k in the Wire class, though I should probably reduce this to 100k to be Arduino compatible for peripherals that cant go faster
To run at 400k you might want to reduce the size of your pull-ups, maybe to 1.5k to 2.2k Ohms
-rick
I think it was defaulted to as fast as bit bang’ably possibly, to demonstrate the speed or the processor, but in hindsight it would be better to set it back to 100k as the default
Shorting Gnd an pin 15.
Now that rtclib and i2c scanner sketch is working,
I wonder how to change pins without changing the libary. and how do I switch over to hardwire ?
I am having trouble with wire library and the I2C scanner also.
by the way I am using Olimexino STM32
Regards,
Luis
Resulting in every adress to reported found with the i2c scanner sketch.
With a sharp pin I cleaned the surronding of the headerpin. Every thing working OK now.

Resulting in every adress to reported found with the i2c scanner sketch.
With a sharp pin I cleaned the surronding of the headerpin. Every thing working OK now.

Next time before I solder the pinheader I will use this inpection.
Leaving me with the question. When i use the wire libary can I define the SDA and SCL pins from the sketch or only in the wire.cpp
// Declare the instance that the users of the library can use
//TwoWire Wire(SCL, SDA, SOFT_FAST);
TwoWire Wire(PB6, PB7, SOFT_FAST);
Not being able to change the pins is a hang over from the AVR Arduino’s which can only use I2C on 2 specific pins.
This is also a bi-product of the global instantiation of the Wire (and this also applies to SPI)
As soon as you include Wire.h, it creates an instance of TwoWire called Wire
You can create another instance of TwoWire in your sketch and use different pins e.g.
TwoWire Wire2(PB4, PB5, SOFT_FAST);
But you can’t get rid of Wire and its always on PB6 and PB7
we have a similar issue with SPI, because even the Maple mini has 2 SPI ports, but its not possible to have “SPI” on port 2
The only reasonable solution I can think of is to have (renamed) duplicates of these classes that omits the global instantiation.
e.g. #include <Wire_NOGLOBAL.h>
I think if we completely removed the global instantiation from Wire (or SPI), a lot of the other libraries that use Wire (or SPI) would break
We could add a menu option to every board which you select to stop global instantiation, but this would not work that well, because you may have some sketches you want to use global instantiation and some you don’t, and you should not need to set a menu each time you load a different sketch, the sketch should be self contained.
I think this whole issue, is possibly something for the arduino.cc programming forum, but I’m not sure they’d be much use, because when I’ve asked questions in the past they have said that these are Non Arduino questions (which is rubbish as I’m using the Arduino IDE)
Not being able to change the pins is a hang over from the AVR Arduino’s which can only use I2C on 2 specific pins.
This is also a bi-product of the global instantiation of the Wire (and this also applies to SPI)
As soon as you include Wire.h, it creates an instance of TwoWire called Wire
You can create another instance of TwoWire in your sketch and use different pins e.g.
TwoWire Wire2(PB4, PB5, SOFT_FAST);
But you can’t get rid of Wire and its always on PB6 and PB7
we have a similar issue with SPI, because even the Maple mini has 2 SPI ports, but its not possible to have “SPI” on port 2
The only reasonable solution I can think of is to have (renamed) duplicates of these classes that omits the global instantiation.
e.g. #include <Wire_NOGLOBAL.h>
I think if we completely removed the global instantiation from Wire (or SPI), a lot of the other libraries that use Wire (or SPI) would break
We could add a menu option to every board which you select to stop global instantiation, but this would not work that well, because you may have some sketches you want to use global instantiation and some you don’t, and you should not need to set a menu each time you load a different sketch, the sketch should be self contained.
I think this whole issue, is possibly something for the arduino.cc programming forum, but I’m not sure they’d be much use, because when I’ve asked questions in the past they have said that these are Non Arduino questions (which is rubbish as I’m using the Arduino IDE)
Only core defines and those setup in the library header are present in the library
(Note. I did investigate this as an option, but it doesn’t work)
Only core defines and those setup in the library header are present in the library
(Note. I did investigate this as an option, but it doesn’t work)
OK.
I’m not sure why this didnt seem to work for me before, or why it seems to work now but I agree, if I have this in the sketch
#define NO_GLOBAL_INSTANTIATION
#include <Wire.h>
I understand your reluctance to #ifdef, but I think in some cases, it is really helpful
I think we need some mechanism to prevent automatic / global instantiation.
This possibly looks like the only way.
I guess we just need to agree on what to call the define.
And I better post this to “General discussion” so it gets a wider audience
Edit.
This doesn’t seem to do what I thought it did. (well I’m sure I looked at this some time ago and eventually came to the conclusion below.
Although in my tests, the Wire global doesn’t seem to be visible to the Sketch if you set that define , this is because its not declaring the extern for it in Wire.h
However, as Wire.h is directly included by Wire.cpp, then Wire.cpp doesnt get the #define.
So Wire.cpp still declares the variable called Wire, its just the sketch cant see it because its not been extern’ed
All the #define does is turn off the visibility of the Wire global variable from inside the sketch.
Hence you can’t declare your own Wire variable in the sketch e.g.
TwoWire Wire(PB8, PB9, SOFT_FAST);
I think we need some mechanism to prevent automatic / global instantiation.
This possibly looks like the only way.
I guess we just need to agree on what to call the define.
And I better post this to “General discussion” so it gets a wider audience
Edit.
This doesn’t seem to do what I thought it did. (well I’m sure I looked at this some time ago and eventually came to the conclusion below.
Although in my tests, the Wire global doesn’t seem to be visible to the Sketch if you set that define , this is because its not declaring the extern for it in Wire.h
However, as Wire.h is directly included by Wire.cpp, then Wire.cpp doesnt get the #define.
So Wire.cpp still declares the variable called Wire, its just the sketch cant see it because its not been extern’ed
All the #define does is turn off the visibility of the Wire global variable from inside the sketch.
Hence you can’t declare your own Wire variable in the sketch e.g.
TwoWire Wire(PB8, PB9, SOFT_FAST);
#define mylib__c
And checked on h to don’t compile code depending on defines, as Wire global, for example. If noglobal is not defined global wire variable will be defined when compiling entire sketch but not available for use on c(pp).
Yes, these are very dirty hacks, but needed to archieve that.
Ah! Only for use on ICs, never for a powerfull machine!
I still can’t see how you managed to control the instantiation in Wire.cpp
I still can’t see how you managed to control the instantiation in Wire.cpp
I still can’t see how you managed to control the instantiation in Wire.cpp
That method had crossed my mind as well, but I had not tried it.
And
_WIRE_C_
really means Wire Global Has Been Defined
Naguissa wrote:
Problem? If Wire is included in any other library global Wire will be defined, but this is logical, as library is included to be used, and usually with that variable.
That method had crossed my mind as well, but I had not tried it.
And
_WIRE_C_
really means Wire Global Has Been Defined
Naguissa wrote:
Problem? If Wire is included in any other library global Wire will be defined, but this is logical, as library is included to be used, and usually with that variable.
I used to work in a corporate environment. I remember all too well having those wall-sized charts created by a team of graphic ants showing system dependencies. They were NEVER right because the systems changed quicker than the ants could analyze the change logs, update the charts, and reprint. Worthless.
Going down a path where #includes are globally mutually exclusive seems to be a very slippery slope… I propose a new environment variable,
SLIPPERY_WHEN_WET
Ray
I used to work in a corporate environment. I remember all too well having those wall-sized charts created by a team of graphic ants showing system dependencies. They were NEVER right because the systems changed quicker than the ants could analyze the change logs, update the charts, and reprint. Worthless.
Going down a path where #includes are globally mutually exclusive seems to be a very slippery slope… I propose a new environment variable,
SLIPPERY_WHEN_WET
Ray
The other alternative is to write more functions and less libraries. Unless there is a true need to inherit from a library, many prigrams are easier to understand as libraries.
Classe libraries have their place, (in Arduino, easy code reuse) but they can be easiiy overrated. Classes can easily constructed right in the editor.
Ray
The other alternative is to write more functions and less libraries. Unless there is a true need to inherit from a library, many prigrams are easier to understand as libraries.
Classe libraries have their place, (in Arduino, easy code reuse) but they can be easiiy overrated. Classes can easily constructed right in the editor.
Ray
<…>
My case is several sensors wifi-available to read status and logs, so rtc, wifi, sd and stm32 are the base, and sensor handling and actuators are the differences, so I try to envelope same codebase in few libraries and do a sketch for each device.