Bela people,
I'm trying to use a small several line LCD display which has a backpack that communicates via I2C. So I'm using the I2c.h library and I wrote the beginnnings of another library combining the needed LCD commands from arduino examples with the required I2c parts that I modeled after the few examples I could find of Bela programs using I2c. It now compiles and runs with no errors but sends nothing on the I2C bus lines. I checked the address using i2cdetect and when I run that check I can see activity on the bus lines but when I run my program see no activity on the bbus lines and so nothing happens on the display.

I'm not very experienced with C++ so any ideas or help would be very welcome. Here is the entirety of the code:

SunfounderLCD.h

#include <I2c.h>
#include <string>

class SF_LCD : public I2c
{
	public:
		SF_LCD (int bus, int address);  // Constructor.  brings in the bus and address
		void clear();
		void setupLCD();  // sets up things with display, cursor and blink all on
		void writeLCD(std::string text);
	private:
};

SunfounderLCD.cpp

#include <iostream>
#include <SunfounderLCD.h>

I2c myI2c;   // creates an instance of the I2c class

// initialize LCD 
SF_LCD::SF_LCD (int bus, int address) {   // constructor for the LCD object
	myI2c.initI2C_RW(bus, address, 0);   
	usleep(2000);
}

// clear LCD display   needs to send command 0x01
void SF_LCD::clear() {
    uint8_t buf[2] = {0x01, 0};
    write(i2C_file, buf, 1);
	usleep(2000);
}

// setup LCD with display on, cursor on, blink on, needs to send  0x0F
void SF_LCD::setupLCD() {
    uint8_t buf[2] = {0x0F, 0};
    write(i2C_file, buf, 1);
	usleep(2000);
}

// write text to LCD  
void SF_LCD::writeLCD(std::string text) {
	int len = text.length();
	char* buf2 = &text[0];
	write(i2C_file, buf2, len);
}

render.cpp

#include <Bela.h>
#include <SunfounderLCD.h>

SF_LCD myDisplay(1, 0x27); // myDisplay I2C is on bus=1 addr=0x27

bool setup(BelaContext *context, void *userData)
{
	myDisplay.clear();
	myDisplay.setupLCD();
	myDisplay.writeLCD("Hello!");
	return true;
}

void render(BelaContext *context, void *userData)
{
}

void cleanup(BelaContext *context, void *userData)
{
}

    JohnBuschert write(i2C_file, buf, 1);

    calls to write() may fail. You should check the return value and ensure it is not negative. If you did check it you'd probably see that it returns -1 and that the global errno variable is set to EBADF. This is because while your class inherits from I2c, you are not actually initialising the base instance by calling its initI2c_RW() method , rather you are initialising a global myI2c instance of I2c but then your writes go to the base instance's file descriptor i2C_file which has not been initialised and therefore the writes fail. Also using a global variable would mean that multiple instances of your object (e.g.: multiple displays on different busses/addresses) would share the global variable and therefore wouldn't work.

    So, start by removing the global I2c myI2c and replace myI2c.initI2C_RW(bus, address, 0) with, simply, initI2C_RW(bus, address, 0).

    JohnBuschert

    char* buf2 = &text[0];

    this doesn't do what you may think it does. Use this instead:

    const char* buf2 = text.c_str();

    You don't need this:

    JohnBuschert

    #include <iostream>
    a month later

    Thanks Giulio.

    You were enormously helpful! I've been delayed by many other things. But with your fixes I finally got it all working. Now I have a library that can be used to get Bela to talk to most simple 16x2 or 20x4 character LCD displays such as this one I'm using.

    alt text
    This is a Sunfounder 20x4 display I got on Amazon for $12
    Here is a link to my github LCD_I2C folder for anyone that wishes to use this library or give me advice.

    And here is the header file for quick reference:

    /* LCD_I2C.h   version 1.0 2022-10-28
       LCD w I2C writing routines header file
       This library allows Bela to write to a 20x4 LCD display via I2C
       It has been tested and works with the Sunfounder I2C LCD 2004
       It should work with most 16x2 or 20x4 displays that have an I2C backpack
       Specifically those using the HDD44780 and PCF8574T chips which seem to be common.  
       It does the same thing as the LiquidCrystal_I2C library for Arduino and other things but 
       instead of just encapsulating that yet one more time, I rewrote it but included most of 
       the LiquidCrystal_I2C commands for compatibility.
    */
    #include <I2c.h>
    #include <string>
    
    class LCD_I2C : public I2c
    {
    	public:
    		LCD_I2C (int bus, int address);  // Constructor.  For Bela the usual I2C bus is 1, the I2C address depends on your device
    
    	//  standard commands in common with Liquid_Crystal_I2C library
    		void clear();  // clears the display
    		void home();   // returns cursor to row 0 col 0
    		void setCursor(uint8_t row, uint8_t col);  // sets cursor at row(0-3), col(0-20) or whatever size you have
    		void write(std::string text);  // writes text starting at cursor's location
    		void noDisplay();
    		void display();
    		void noBlink();
    		void blink();
    		void noCursor();
    		void cursor();
    		void noBacklight();
    		void backlight();
    		void begin();  // unneeded null function kept only for compatibilty
    
    	//  new commands
    		void setCursorWrite(uint8_t row, uint8_t col, std::string text);  // sets cursor to coords and then writes text
    		void mode(int backlight, int display, int cursor, int blink); // 1 or 0 sets all these on or off
    		
    	/*	not yet implemented from LiquidCrystal_I2C library
    		scrollDisplayLeft
    		scrollDisplayRight
    		printLeft
    		printRight
    		ledftToRight
    		RightToLeft
    		shiftIncrement
    		shiftDecrement
    		autoScroll
    		noAutoScroll
    		createChar
    		printRight
    		init
    		oled_init
    	*/
    
    	private:
    
    	//  Lower level commands that differ from LiquidCrystal_I2C
    		void sendChar(uint8_t);
    		void sendCommand(uint8_t hiNib, uint8_t loNib);
    		void sendNibble(uint8_t nib, uint8_t rs);
    		void transmit(uint8_t byte);
    
    		uint8_t buf[2] = {0,0};  // buffer for characters pass to I2c write (it wants an array, maybe could have been a pointer)		
    		uint8_t nibble =0;
    		uint8_t hiNib = 0;
    		uint8_t loNib = 0;  
    		int gbacklight = 1;  // default value when started
    		int gdisplay = 1;  
    		int gcursor = 1;
    		int gblink = 1; 
    		uint8_t homeAddress[4] = {0x00, 0x40, 0x14, 0x54};   // beginning address of each line for 2 or 4 line displays
    		
    		
    
    };