ProMicro and I2C

I am about to start my first I2C experiment on the ProMicro Leonardo.

I built a PCB that breaks out the pins on the ProMicro and it all seems to be working.

Unfortunately, I only gave myself access to 5, 6, A0, A1, A2 and A3. The rest of the pins on the ProMicro already have dedicated functions.

Now that I would like to hook up an I2C 2X16 display, I see that the hardware SDA and SCL are already being used by onboard LEDs that I cannot give up.

Are there any libraries that allow me to use any of the pins I have remaining to operate my I2C device?



I am new to Arduino. I googled just about everything I could think of. What I learned from your reply is that a "soft I2C" is the description of what I am looking for. Sorry I didn't know that. I do now.

Thanks for your reply..

Here is a list: Arduino I2C libraries · Testato/SoftwareWire Wiki · GitHub. It is too much, I know.
Perhaps you have to alter the LCD library and other libraries, because they all use the Arduino Wire library. A software I2C has consequences for the I2C bus when a cable is used (by the way, don’t use a cable for I2C).
In the end it is easier to: “Just remake the PCB!” as spycatcher2k wrote.

You can tell us what your project is, show us the schematic and the sketch and photos, and maybe you get good advice.


I have no problem remaking the board but there have been so many rules how I can use pins. Something always has to go to get something I want. (smile)

My board is primarily designed to receive a 20 byte serial command and perform a few functions. The serial command is the control sequence for my 1/8th scale railroad. This is train I can ride that runs on 7.5" wide track. Its a big sucker.

Each car on my train is to get one of these boards so there can be functions like clearance lights, backup lights, or whatever I can think of, on the system. Therefore, I was trying to make a generic board that would work on every car.

I came up with the idea to use the I2C 2X16 display to show me the status of ALL 20 bytes in English and with nice decimal numbers. Now I am trying to figure out how to get the job done.

Koepel, when you say "don't use a cable" do you mean "keep the I2C wires short"?

There goes my L1 and L2. They are sitting on the I2C pins. I like the PWM function on one so I can modulate the LED which shows me something I like to see. I'll figure something out.

Even though my system runs quite slow (serial updates are about 7 times a second) does everyone still recommend I stay away from Soft I2C?



Yes, I mean short I2C wires. No, you don't have to stay away from software I2C. If you are not planning any I2C sensors, and it is only the I2C display, then it can be done with some small changes to the I2C display library.

You have used every pin :confused:

The analog inputs are also digital pins as far as I know. That means you should be able to run a software I2C with any two of the analog pins.

It is possible to use a software PWM library, to dim a led on any pin. That requires a timer with interrupt.

My advice is to make a new board, perhaps with the Micro instead of the Pro Micro. Second best is the SoftwareWire or the SlowSoftWire on two analog pins for the I2C display.

When you change the I2C display library, you have to be carefull how you organize your files. You should rename the changed library. When the I2C display has an update with bugs removed, you don't get them. You could copy the changed files into your project, so that they will appear on new tabs in the Arduino IDE.

It is possible to use the RX and TX led on the Arduino Pro Micro. When the Serial port is used, they will be overidden, but it is possible to use them. I switch them between INPUT (off) and OUTPUT LOW (on). Their pin numbers are LED_BUILTIN_TX and LED_BUILTIN_RX. The first thing I do is to turn them off, because they are so bright.

The design of the Pro Micro has a flaw. When you have soldered the T1 for 5V, and connect the power to RAW and connect the USB to a computer, then it is possible that current can flow into the computer.

Koepel: The design of the Pro Micro has a flaw. When you have soldered the T1 for 5V, and connect the power to RAW and connect the USB to a computer, then it is possible that current can flow into the computer.

This took me quite a bit of time to discover.

My schematic above is the way I made my PCB but the one "trace bash" I had to do was change the power source of the ProMicro to my onboard reg 5V.

I always suspected that 12V to the RAW might be a bit much for the onboard regulator but all the specs indicated that it would be fine.

The first time I fired it up, it blew up one of my ProMicro boards. I very carefully tested and then found that the 3 other ProMicro boards would work with 12V on the RAW pin, but the onboard regulator got really hot.

I cut a few traces and now I am feeding the ProMicro with Reg 5V to the VCC pin.

After ringing out the power section of my ProMicros, I decided to leave the 5v solder tabs open. That part is working fine.

Thanks for all the other good suggestions. This really helps me.


Hi, Pin 3 and 2 are the I2C, it would be worthwhile freeing those pins up for I2C in case you want to add extra I2C hardware including I/O expansion.

You say your other pins are being used but the schematic does not show what they are doing? ie D11, D12 and D13.

If you are worried about power supply for your micro, you could use a DC-DC converter, 12V to 5V, it would also provide some powersupply noise immunity.

As an example;

I like the project, my cousin has built a garden railway after he retired.

My Dad, brother and I in our childhood and teens were HO/OO modelers on GWR theme. 20ft x 12ft shed, when us kids left home Dad kept improving it and was his man-cave.

Tom... :)

There are two other things I have learned about using the ProMicro. One was already mentioned. The superbright onboard LEDs.

I use this to turn them off:

// This line keeps the superbright ProMicro LEDs from staying on all the time
digitalWrite(17, HIGH); // Turn off RXLED
TXLED0; // Turn off TXLED

The other is that on my board, I have a MAX232 attached to Serial1 and if I do not initialize Serial1.begin(9600) or some baud rate, even if you are not going to use it, the output RX pin comes up Output and the Max232 Output start beating each other up and, in my case, the Max232 got so hot it would burn my finger.

So, on my little PCB I have to initialize both serial ports for every application, unless I want to pull the Max232 off the board.


I suspect that your first line could have been RXLED0; ;) It would give a more consistent feel to your code.

Pins D0 and D1 should be input after reset; maybe the ProMicro bootloader dropped a stitch when handing over to the user code (although it should not have a need to use them as outputs).

I read somewhere on this forum that you couldn't use the same command for both pins. Now that you mention it, I will give it a try.

Another good thing I learned today. THANKS

BTW -- Here's my PCB -- I use RJ45 for my RS232. Board gets +12 from that cable as well.


gmcmurry: I read somewhere on this forum that you couldn't use the same command for both pins. Now that you mention it, I will give it a try.

If you look closely, it's not the same commands ;)

I prefer using the LED_BUILTIN_TX and LED_BUILTIN_RX and use the normal pinMode() and digitalWrite(), not the real numbers or the RXLED0 macro's.

Perhaps the MAX232 is oscillating at a very high frequency when the D1 is not set as output yet. Does it have some kind of internal pullup ?

There is one thing I forgot to mention. I did not install any extra boards from Sparkfun. I like to stay as much as possible close to the official Arduino board and the official updates and bug fixes. Therefor I have burned the bootloader of the Micro into the Pro Micro and in the menu I select the Micro.

sterretje: RXLED0; and TXLED0;

confirmed -- these commands work fine. I do not have to use the direct pin command as I originally read.


Always good to simplify and learn new stuff.

Also, MAX232 have internal pullups on both the ttl inputs as well as the RS232 inputs.


There are a couple of things that you should keep in mind if you do decide to try and go down the s/w i2c path to be able to use other pins for i2c.
While there are s/w i2c libraries that do work quite well and do provide a Wire compatible API, they don’t work exactly like the real thing.
They are never as fast, but lower speed typically isn’t an issue for many uses.

The biggest issue is that in Arduino, just like in Windows s/w, many s/w developers hard code things and/or make assumptions about the environment.
Because of this you will likely run into issues where the library for your i2c slave device won’t work with a s/w i2c library as it assumes using Wire.
While sometimes this can be corrected with minor modifications to the i2c slave device library code, in others can be very difficult.
The amount of incompatibility with a s/w i2c library and the amount of work to fix it can vary from none, to LOTs depending on the i2c device library and the particular s/w i2c library used.
For example, even if a s/w i2c library provides all the same API functions, and an i2c object named Wire, with the newer IDE capabilities a library can include headers for its sub-libraries. If the library takes advantage of that and includes <Wire.h> then it has made the assumption to use the Wire library and you would have to modify it to use it.
From the i2c slave device libraries I’ve looked at, very few work “out of the box” with a s/w i2c library, and those that do only work with certain ones.

Because of the s/w issues related to using Wire vs a s/w i2c library, you may be better off modifying the h/w to be able to use the h/w i2c pins for i2c so that the Wire library can be used. Depending on your devices and use cases and the libraries involved, it may actually be less work in the long run.

— bill

That is why I choose these two: SoftwareWire : at the default 100kHz I2C speed, Wire API compatible, allows clock pulse stretching (not needed for a display). SlowSoftWire : Wire APi compatible, uses standard Arduino functions, 100% compatible with all platforms.

Koepel: That is why I choose these two: SoftwareWire : at the default 100kHz I2C speed, Wire API compatible, allows clock pulse stretching (not needed for a display). SlowSoftWire : Wire APi compatible, uses standard Arduino functions, 100% compatible with all platforms.

Just being Wire API compatible often isn't enough when using libraries for i2c slave devices. I've used SoftwareWire which works well on the AVR cores, but it can still have issues and/or require modifying the i2c slave device library to be able to use it. For example, consider these 3 popular i2c backpack lcd libraries: - newLiquidCrystal won't work with it. (assumes Wire library) - LiquidCrystal_I2C library won't work with it (assumes Wire library) - hd44780 hd44780_I2Cexp class works with no modifications to the library but assumes i2c object named Wire.

The hd44780 library can work with s/w i2c libraries including all the auto locate and auto detection capabilities. In order to use a s/w i2c library with hd44780, you must declare the s/w i2c object named "Wire" or create a #define named Wire to remap the actual name of the s/w i2c object to Wire and do either of these above the hd44780 library includes in the sketch. There are some limitations like it is difficult or potentially impossible to use both the h/w Wire library and a s/w i2c library when wanting to use hd44780 with the s/w i2c library. But if the h/w Wire library is not going to be used, then it is pretty easy to get the hd44780_I2Cexp i/o class working with a s/w i2c library that provides a Wire compatible API.

This is not the case for the other i2c backpack libraries.

--- bill


Sometimes removing the #include <Wire.h> with a software library and declaring or defining a new “Wire” object is enough. But I don’t like that solution.
That is probably what @gmcmurry has to do when he chooses a software I2C library.

Most libraries for I2C sensors (or displays) do not even allow “Wire1” for example.

The best solution would be to let a library use any hardware or software Wire library. That is what c++ is invented for.

I would vote for a complete redesign of the Wire library, but that is probably not going to happen.

Right now, I just would just like a way, when speed isn’t a requirement, to be able to talk to an I2C powered 2X16 LCD display using non-I2C dedicated pins on the ProMicro.

For that, the easiest way will be to use an LCD with a PCF8574 backkpack and then use my hd44780 library package with the hd44780_I2Cexp i/o class and the SoftwareWire library.

You can’t get there with the other i2c backpack LCD libraries, unless you do quite a bit of editing on them.

After you install the SoftwareWire library and the hd44780 library (Use the IDE library manager to install them both directly from the IDE - no messing with zip files)
all you have to do is change the Wire include and add your SoftwareWire i2c object named Wire.
After that, it will “just work”. The hd44780 library will auto locate the i2c address of the backpack and auto detect the pin mappings and backlight active level used on the backpack and will self configure itself.

In any of the included hd44780_I2Cexp i/o class examples,
Change this line:

#include <Wire.h>


#include <SoftwareWire.h>
SoftwareWire Wire(YOUR_SDA_PIN, YOUR_SCL_PIN);

That’s it and the example sketch should “just work”.
The one exception will be the I2CexpDiag sketch. It assumes using the hardware SDA and SCL pins defined in the variant file. It could be tweaked to use custom pins used with SoftwarwareWire but “as is” it won’t work.

You can read more about the hd44780 library package on its github page: GitHub - duinoWitchery/hd44780: Extensible hd44780 LCD library

— bill