[SOLVED] LCD (1602, I2C) on ATtiny841

Hi all,

Looking for suggestions on how to get a standard 1602 LCD screen with I2C backpack to work on an ATtiny. Surprisingly little information on the subject, even when looking at it’s direct predecessor, the ATtiny84a.

I’m using ATtinycore, and trying to use the built-in Wire library and the LiquidCrystal_I2C library. This doesn’t even compile: turns out the problem is that the 841 doesn’t have I2C master hardware, so that’s done in software, and that’s clashing with the LiquidCrystal_I2C library.

Then I ran into the LiquidCrystal_I2C_BitBang but unfortunately no luck there, either… Nothing appears on the display. I can’t even get the backlight to blink on and off!

The display is correctly recognised as I2C device on the scanner (which I had to modify to make work on the ATtiny841: the String class and trying to store too much information before printing got in the way).

For whom it may be interesting, hereby my I2C scanner code for ATtiny:

#include <Wire.h>

void setup() {
  Serial.begin(9600);
  Wire.begin();
}  // end of setup

void loop() {
  byte count = 0;
  for (byte i = 1; i < 120; i++) {
    Wire.beginTransmission(i);
    if (Wire.endTransmission() == 0) {
      Serial.print(F("Found address: "));
      Serial.print(i);
      char s[3];
      sprintf(s, " (0x%02x", i);      
      Serial.print(s);
      Serial.println(F(")"));
      count++;
      delay(50);  // Wait for the printing to complete.
    } // end of good response
  } // end of for loop
  Serial.println(F("Done."));
  Serial.print(F("Found "));
  Serial.print(count, DEC);
  Serial.println(F(" device(s)."));
  Serial.println();
  delay(2000);
}

What I also found out already is that the SPI connections do interfere with the I2C - not sure why, but the scanner works best when the SPI is disconnected (using a Pro Micro as SPI programmer - it’s as if the pins are not set to INPUT when the programmer is finished).

What I also found out already is that the SPI connections do interfere with the I2C - not sure why, but the scanner works best when the SPI is disconnected (using a Pro Micro as SPI programmer - it's as if the pins are not set to INPUT when the programmer is finished).

The ATtiny family does have hardware support for SPI and I2C but that support is not directly comparable with the support the ATmega family offers. In the Tiny world USI (Universal Serial Interface) is responsible to provide that hardware support for both interface types. That also means you cannot use both on the same chip.

I'm using ATtinycore, and trying to use the built-in Wire library and the LiquidCrystal_I2C library. This doesn't even compile: turns out the problem is that the 841 doesn't have I2C master hardware, so that's done in software, and that's clashing with the LiquidCrystal_I2C library.

On my machine the HelloWorld example of LiquidCrystal_I2C compiles without an error for the ATtiny841(optiboot). Please post the code that fails for you.

That should be ISP, not SPI… I know can’t use both (SDA and SCL pins are shared), but the programmer does use those two pins as well, no way around that. However if the ArduinoISP sets the pins to INPUT when finished, there should be no problem.

My I2C test sketch, works on Arduino & NodeMCU:

#include <Wire.h>
#include <LCD.h>
#include <LiquidCrystal_I2C.h>  // F Malpartida's NewLiquidCrystal library

#define I2C_ADDR    0x27  // Define I2C Address for controller
#define En_pin 2
#define Rw_pin 1
#define Rs_pin 0
#define D4_pin 4
#define D5_pin 5
#define D6_pin 6
#define D7_pin 7
#define BACKLIGHT_PIN 3

#define  LED_OFF  0
#define  LED_ON  1
LiquidCrystal_I2C lcd(I2C_ADDR, En_pin, Rw_pin, Rs_pin, D4_pin, D5_pin, D6_pin, D7_pin);

void setup()
{
  lcd.begin (16, 2); // initialize the lcd
  // Switch on the backlight
  lcd.setBacklightPin(BACKLIGHT_PIN, POSITIVE);
  lcd.setBacklight(LED_OFF);
}

void loop()
{

  // Reset the display
  lcd.clear();
  lcd.setBacklight(LOW);
  delay(1000);
  lcd.home();

  // Print on the LCD
  lcd.backlight();
  lcd.setBacklight(HIGH);
  lcd.setCursor(0, 0);
  lcd.print("City Hydroponics");
  delay(8000);
}

Fails with these error messages; all multiple definition errors:

Arduino: 1.8.5 (Linux), Board: "ATtiny441/841 (No bootloader), ATtiny841, Disabled, 12 MHz (external), EEPROM retained, B.O.D. Enabled (1.8v), B.O.D. Disabled, B.O.D. Disabled"

libraries/NewLiquidCrystal/SI2CIO.cpp.o: In function `ass_i2c_delay_half':
/home/wouter/Arduino/libraries/NewLiquidCrystal/SoftI2CMaster.h:196: multiple definition of `ass_i2c_delay_half'
libraries/Wire/Wire.cpp.o:/home/wouter/Arduino/libraries/NewLiquidCrystal/SoftI2CMaster.h:196: first defined here
libraries/NewLiquidCrystal/SI2CIO.cpp.o: In function `ass_i2c_delay_half':
/home/wouter/Arduino/libraries/NewLiquidCrystal/SoftI2CMaster.h:196: multiple definition of `ass_i2c_wait_scl_high'
libraries/Wire/Wire.cpp.o:/home/wouter/.arduino15/packages/ATTinyCore/hardware/avr/1.1.5/libraries/Wire/src/SoftWire.h:101: first defined here
libraries/NewLiquidCrystal/SI2CIO.cpp.o: In function `ass_i2c_delay_half':
/home/wouter/Arduino/libraries/NewLiquidCrystal/SoftI2CMaster.h:196: multiple definition of `i2c_init()'
libraries/Wire/Wire.cpp.o:/home/wouter/.arduino15/packages/ATTinyCore/hardware/avr/1.1.5/libraries/Wire/src/SoftWire.h:101: first defined here
libraries/NewLiquidCrystal/SI2CIO.cpp.o: In function `ass_i2c_delay_half':
/home/wouter/Arduino/libraries/NewLiquidCrystal/SoftI2CMaster.h:196: multiple definition of `i2c_start(unsigned char)'
libraries/Wire/Wire.cpp.o:/home/wouter/.arduino15/packages/ATTinyCore/hardware/avr/1.1.5/libraries/Wire/src/SoftWire.h:101: first defined here
libraries/NewLiquidCrystal/SI2CIO.cpp.o: In function `ass_i2c_delay_half':
/home/wouter/Arduino/libraries/NewLiquidCrystal/SoftI2CMaster.h:196: multiple definition of `ass_i2c_write'
libraries/Wire/Wire.cpp.o:/home/wouter/.arduino15/packages/ATTinyCore/hardware/avr/1.1.5/libraries/Wire/src/SoftWire.h:101: first defined here
libraries/NewLiquidCrystal/SI2CIO.cpp.o: In function `ass_i2c_delay_half':
/home/wouter/Arduino/libraries/NewLiquidCrystal/SoftI2CMaster.h:196: multiple definition of `i2c_rep_start(unsigned char)'
libraries/Wire/Wire.cpp.o:/home/wouter/.arduino15/packages/ATTinyCore/hardware/avr/1.1.5/libraries/Wire/src/SoftWire.h:101: first defined here
libraries/NewLiquidCrystal/SI2CIO.cpp.o: In function `ass_i2c_delay_half':
/home/wouter/Arduino/libraries/NewLiquidCrystal/SoftI2CMaster.h:196: multiple definition of `i2c_start_wait(unsigned char)'
libraries/Wire/Wire.cpp.o:/home/wouter/.arduino15/packages/ATTinyCore/hardware/avr/1.1.5/libraries/Wire/src/SoftWire.h:101: first defined here
libraries/NewLiquidCrystal/SI2CIO.cpp.o: In function `ass_i2c_delay_half':
/home/wouter/Arduino/libraries/NewLiquidCrystal/SoftI2CMaster.h:196: multiple definition of `ass_i2c_stop'
libraries/Wire/Wire.cpp.o:/home/wouter/.arduino15/packages/ATTinyCore/hardware/avr/1.1.5/libraries/Wire/src/SoftWire.h:101: first defined here
libraries/NewLiquidCrystal/SI2CIO.cpp.o: In function `ass_i2c_delay_half':
/home/wouter/Arduino/libraries/NewLiquidCrystal/SoftI2CMaster.h:196: multiple definition of `i2c_read(bool)'
libraries/Wire/Wire.cpp.o:/home/wouter/.arduino15/packages/ATTinyCore/hardware/avr/1.1.5/libraries/Wire/src/SoftWire.h:101: first defined here
collect2: error: ld returned 1 exit status
exit status 1
Error compiling for board ATtiny441/841 (No bootloader).

This report would have more information with
"Show verbose output during compilation"
option enabled in File -> Preferences.

Compiling with the Optiboot option makes no difference.

If you use the LiquidCrystal_I2C library that the library manager offers, it compiles without a problem. It looks like two software I2C emulations clashes in your setup.

Mmm... It seems I have a library issue or so then... Getting other errors now - other parts missing suddenly. Thanks for the confirmation that at least it can compile, that's something :-)

So, cleaned up all liquidcrystal libraries from my ~/Arduino/Libraries folder.

Re-installed the built-in Arduino LiquidCrystal library (version 1.0.7), just to make sure Installed LiquidCrystal I2C by Frank de Brabander (version 1.1.2).

This failed to compile for any board: LCD.h not found.

Turns out that belongs to NewLiquidCrystal which served me quite well on the Pro Micro and NodeMCU. So installed that one again.

Now it compiles when I set my board to Pro Micro or Uno, but not when I set it to ATtiny841. The same error messages as posted above still appear.

Indeed it looks very much like two software I2C implementations clash - but I wonder where the second could possibly be? I do expect that an LCD library does not try to implement a software I2C, but instead will just try to use the standard Wire library, and let Wire figure out how the I2C works under the hood.

I also tried LiquidCrystal_I2C_BitBang which appears to indeed have its own software I2C. That one actually compiles, but the display doesn't react at all to commands (backlight on/off, printing text).

ndeed it looks very much like two software I2C implementations clash - but I wonder where the second could possibly be? I do expect that an LCD library does not try to implement a software I2C, but instead will just try to use the standard Wire library, and let Wire figure out how the I2C works under the hood.

You NewLiquidCrystal library include SoftI2CMaster which is a software I2C emulation. And the ATtiny core also has a software I2C emulation.

Remove the LCD.h from your sketch and use the included version of LiquidCrystal_I2C, that one works with the Wire library provided by the ATtinycore.

Finally, it works! Thanks for the pointers.

Final software setup with Arduino 1.8.5, installed libraries:
LiquidCrystal 1.0.7
LiquidCrystal_I2C 1.1.2

Test sketch:

#include <Wire.h> 
#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x27, 16, 2);  // set the LCD address to 0x27 for a 16 chars and 2 line display

void setup()
{
  lcd.init();                      // initialize the lcd 

  // Print a message to the LCD.
  lcd.backlight();
  lcd.setCursor(0,0);
  lcd.print(F("  Hello, world! "));
  lcd.setCursor(0,1);
  lcd.print(F(" LCD - I2C 1602 "));
}


void loop()
{
}

At just under 3 kB it would fit on a 441 even. Hope this is useful for others as well.