I2c display not working in any ways on Cerbuino NET

Hi to everybody,
I’ve read a lot of topics and user’s code contributions but I still missing something in get I2C display working on CerbuinoNET. The display is a Sainsmart LCD2004 module (http://www.sainsmart.com/sainsmart-iic-i2c-twi-serial-2004-20x4-lcd-module-shield-for-arduino-uno-mega-r3.html), i’ve already tested it with arduino uno and it works very well and with no hassle, all setup takes literally 10 seconds.
But with my cerbuino is another story. First I tried with HW i2c on socket #2: i used a tb10 breakout module to connect cerbuino board and display and followed all examples by ghi but I don’t see any character on the display. I see backlight on so i suppose that is not a power problem. I tried several approaches, with an array of i2c transaction and with single transactions (following the post by Bec A Fuel), still no characters on the display.
Then I tried SW i2c, SDA and SCL on first two digital pins (D0 and D1) and with different pull-up resistors (1.8k, 2.2k and 4.7k): same story, display powered, number of succesfully written bytes is not zero but still no characters on the display. I also tried to choose a different couple of digital pins but no success.
Please can someone help me on this apparently easy task? I’ve spent a lot of days on this problem with almost zero progresses.
Thank you so much!

What address did you use? The 7 bit address is always confusing.

And this is our i2c page
https://www.ghielectronics.com/docs/12/i2c

@ lopos - here’s some example code. Please remember that i copy paste most important code from a source to this example. The example below as whole was not tested, but i guess it will get you going.


 [Flags]
        private enum NxpPcf8584
        {
            RegisterSelect = 0x1,
            ReadWrite = 0x2,
            Enable = 0x4,
            BackLight = 0x8,
            DataBit4 = 0x10,
            DataBit5 = 0x20,
            DataBit6 = 0x30,
            DataBit7 = 0x40,
        }


    public class Lcd16X2I2C
    {
        private byte _backLightMask = (byte) NxpPcf8584.BackLight;
        private readonly I2CDevice _display;
        private readonly object _displayLock = new object();
        private readonly I2CDevice.I2CTransaction[] _i2CTransaction = new I2CDevice.I2CTransaction[1];
        private readonly byte[] _i2CWriteBuffer4 = new byte[4];
        private byte _displayControl = 0x04; // display on, no cursor, non blinking cursor
        
        public Lcd16X2I2C(UInt16 i2CAddress)
        {
            _display = new I2CDevice(new I2CDevice.Configuration(i2CAddress, 100));

            // Init IO pins 
            var ioBuffer = new byte[1];
            ioBuffer[0] = (byte) (NxpPcf8584.Enable | NxpPcf8584.RegisterSelect | NxpPcf8584.BackLight);
            var transaction = new I2CDevice.I2CTransaction[1];
            transaction[0] = I2CDevice.CreateWriteTransaction(ioBuffer);
            if (_display.Execute(transaction, 1000) != 1)
                throw new Exception("IO Error LDC init");

            SendCmd(0x33);
            SendCmd(0x32);
            DisplayOn();
            Clear();
        }

        
        private void SendCmd(byte cmdCode)
        {
            var tmp = (byte) ((cmdCode & 0xF0) | _backLightMask);
            _i2CWriteBuffer4[0] = (byte) (tmp | (byte) NxpPcf8584.Enable); // high nibble data + RegisterSelect-Low + Enable-high
            _i2CWriteBuffer4[1] = tmp; // high nibble data + RegisterSelect-Low + Enable-Low
            cmdCode <<= 4;
            cmdCode |= _backLightMask;
            _i2CWriteBuffer4[2] = (byte) (cmdCode | (byte) NxpPcf8584.Enable); // low nibble data + RegisterSelect-Low + Enable-high
            _i2CWriteBuffer4[3] = cmdCode; // low nibble data + RegisterSelect-Low + Enable-Low
            _i2CTransaction[0] = I2CDevice.CreateWriteTransaction(_i2CWriteBuffer4);
            int cnt = _display.Execute(_i2CTransaction, 1000);
            if (cnt != _i2CWriteBuffer4.Length)
                throw new Exception("I2C write error. Bytes written: " + cnt);

            Thread.Sleep(1);
        }

        private void SendDisplayData(byte data)
        {
            var tmp = (byte) ((data & 0xF0) | _backLightMask | (byte) NxpPcf8584.RegisterSelect);
            _i2CWriteBuffer4[0] = (byte) (tmp | (byte) NxpPcf8584.Enable); // high nibble data + RegisterSelect-High + Enable-high
            _i2CWriteBuffer4[1] = tmp; // high nibble data + RegisterSelect-High + Enable-Low
            data <<= 4;
            data |= (byte) (_backLightMask | (byte) NxpPcf8584.RegisterSelect);
            _i2CWriteBuffer4[2] = (byte) (data | (byte) NxpPcf8584.Enable); // low nibble data + RegisterSelect-High + Enable-high
            _i2CWriteBuffer4[3] = data; // low nibble data + RegisterSelect-High + Enable-Low
            _i2CTransaction[0] = I2CDevice.CreateWriteTransaction(_i2CWriteBuffer4);
            if (_display.Execute(_i2CTransaction, 1000) != _i2CWriteBuffer4.Length)
                throw new Exception("I2C write error");
        }

        /// <summary>
        ///     Set the lcd display on or off
        /// </summary>
        /// <param name="mode">true=on, false=off</param>
        public void DisplayOn(bool mode = true)
        {
            if (mode)
            {
                _displayControl |= 0x04;
            }
            else
            {
                _displayControl = (byte) (_displayControl & ~0x04);
            }
            SendCmd((byte) (_displayControl | 0x08));
        }

        /// <summary>
        ///     Turn the curson on or off
        /// </summary>
        /// <param name="mode">true=on, false=off</param>
        public void CursonOn(bool mode = true)
        {
            lock (_displayLock)
            {
                if (mode)
                    _displayControl |= 0x02;
                else
                    _displayControl = (byte) (_displayControl & ~0x02);

                SendCmd((byte) (_displayControl | 0x08));
            }
        }

        /// <summary>
        ///     Set the cursor blinking mode
        /// </summary>
        /// <param name="mode">true=blinking, false=non blinking</param>
        public void CursorBlink(bool mode = true)
        {
            lock (_displayLock)
            {
                if (mode)
                    _displayControl |= 0x01;
                else
                    _displayControl = (byte) (_displayControl & ~0x01);

                SendCmd((byte) (_displayControl | 0x08));
            }
        }

        /// <summary>
        ///     Write a string at the current cursor location
        /// </summary>
        /// <param name="text"></param>
        public void PrintString(string text)
        {
            lock (_displayLock)
            {
                for (int index = 0; index < text.Length; ++index)
                    Putc((byte) text[index]);
            }
        }

  /// <summary>
        ///     Write a character at the current cursor location.
        ///     The cursor wil advance to the next location.
        /// </summary>
        /// <param name="c"></param>
        public void Putc(byte c)
        {
            lock (_displayLock)
            {
                SendDisplayData(c);
                //WriteNibble((byte)((uint)c >> 4)); // High nibble
                //WriteNibble(c); // low nibble
            }
        }
}

In your main code use 

   var lcdDisplay = new Lcd16X2I2C(0x27);
   lcdDisplay.PrintString("Hello");



Hi guys,
@ Gus i’ve checked with Arduino that the address i’m using was correct (0x27).

@ RobvanSchelven many many thanks for your help, with your example i’ve succesfully write something on the display for the first time! But I’ve one question: all ghi posts and resources on this subject usually report 4-lines examples like this:

I2CDevice.Configuration con = new I2CDevice.Configuration(0x27, 400);
I2CDevice MyI2C = new I2CDevice(con);
I2CDevice.I2CTransaction[] xActions = new I2CDevice.I2CTransaction[1];
xActions[0] =I2CDevice.CreateWriteTransaction(System.Text.Encoding.UTF8.GetBytes(SOMETEXT);
MyI2C.Execute(xActions, 1000);

or for SW I2C:

Cpu.Pin I2C_SDA = CerbuinoPins.D1;
Cpu.Pin I2C_SCL = CerbuinoPins.D0;
SoftwareI2CBus bus = new SoftwareI2CBus(I2C_SCL, I2C_SDA);
SoftwareI2CBus.I2CDevice device = bus.CreateI2CDevice(0x27, 0);
byte[] data = Encoding.UTF8.GetBytes(“ciao”);
int bytesSent = device.Write(data, 0, data.Length);

so, how do you figured out how to reach this complex goal? And can you or someone else point me to a good tutorial to acquire these vital informations?

ps: my display is a 20x4, so how i had to change your snippet to use all rows and columns? and is there a direct method to clear the display (without loop all 20x4 chars)?

Thank you so much, really, i’m sincerely grateful to you and other guys of this forum.

You have to look at the controlling chip on the device to really understand what needs to be done and what commands you need to send. You can almost guarantee that you won’t be able to send text like
xActions[0] =I2CDevice.CreateWriteTransaction(System.Text.Encoding.UTF8.GetBytes(SOMETEXT);
or
int bytesSent = device.Write(data, 0, data.Length);

most displays like these need some form of control signal and then the data, or control or mixed in with the data. If you look in the PrintString chain, it calls into SendDisplayData for each character, this splits out the actual data, merges in the control signals, and then sends it in 4 bytes - all for a single character.

as for the 20x4 setup, you may need to look at the command structure the display uses.