New to I2C and could do with some help please

You know what it’s like. New device that you want to work with because someone said it would be easy and used fewer I/O lines. Well, that’s me right now. I have a new I2C LCD that just arrived from Farnell (http://uk.farnell.com/midas/mccog21605d6w-sptlyi/lcd-cog-2x16-stn-grn-b-l-i2c/dp/2063205?Ntt=2063205) Pretty cheap and there seems to be some documentation available (http://www.farnell.com/datasheets/1485481.pdf).

Now not only is this my first I2C LCD project, but it’s my first time with anything I2C. I’m using my Spider and have connected an extender to port 4 (IKU X). I’ve brought out pins 8 (SDA) and 9 (SCK) according to the Spider Schematic (http://www.ghielectronics.com/downloads/schematic/FEZ_Spider_Mainboard_SCH.PDF). The docs say that LCD has an I2C address of 0111110b, which when right shifted becomes 01111100b (0x7C). SO I setup my I2C like this


I2CConfig = new I2CDevice.Configuration(0x7c, 100);
I2C = new I2CDevice(I2CConfig);

So, first question, how do I know that this is using I2C_1 on the Spider (Port 4) and not I2C_2 (Port 10)?

And then I want to initialise the device, send it some text, etc. So I create a function to follow the initialise routine on page 9 of the manual for 3v3 operation, throwing some sleeps in for good measure:


var xActions = new I2CDevice.I2CTransaction[1];

xActions[0] = I2CDevice.CreateWriteTransaction(new byte[] { 0x0, 0x38 });
I2C.Execute(xActions, 1000);
Thread.Sleep(100);

xActions[0] = I2CDevice.CreateWriteTransaction(new byte[] { 0x0, 0x39 });
I2C.Execute(xActions, 1000);
Thread.Sleep(100);

xActions[0] = I2CDevice.CreateWriteTransaction(new byte[] { 0x0, 0x14 });
I2C.Execute(xActions, 1000);
Thread.Sleep(100);

xActions[0] = I2CDevice.CreateWriteTransaction(new byte[] { 0x0, 0x74 });
I2C.Execute(xActions, 1000);
Thread.Sleep(100);

xActions[0] = I2CDevice.CreateWriteTransaction(new byte[] { 0x0, 0x54 });
I2C.Execute(xActions, 1000);
Thread.Sleep(100);

xActions[0] = I2CDevice.CreateWriteTransaction(new byte[] { 0x0, 0x6F });
I2C.Execute(xActions, 1000);
Thread.Sleep(100);

xActions[0] = I2CDevice.CreateWriteTransaction(new byte[] { 0x0, 0x0C });
I2C.Execute(xActions, 1000);
Thread.Sleep(100);

xActions[0] = I2CDevice.CreateWriteTransaction(new byte[] { 0x0, 0x01 });
I2C.Execute(xActions, 1000);
Thread.Sleep(100);

And I get nothing, no blinking cursor or anything.

I try to send it some text


public void Write(string sText)
{   
    var xActions = new I2CDevice.I2CTransaction[1];
    byte[] buf = Encoding.UTF8.GetBytes(sText);                 // Convert the string to array
    xActions[0] = I2CDevice.CreateWriteTransaction(buf);
    I2C.Execute(xActions, 1000);
}

and still nothing.

So is it my hardware, is it my software? How will I ever find out?

Has anyone any experience of addressing I2C LCD devices, ideally the Midas devices? Or what about I2C experience that can point me in the right direction to help get this sorted out?

Thanks in advance.

https://www.ghielectronics.com/docs/12/i2c describes what Andre points out - you must use the 7-bit address in netmf.

1 Like

Well, some reasonable progress tonight. Got the display working (thanks @ Brett and @ andre.m) having spent some more time in the manual.

However, when I send the string “Hello World!!!” the display shows “ello World!!!”

I’ve moved things about (left and right) to see if it’s an address thing. Moved it to the second line and even trued inserting a single character into the display to try and change it to “Hallo World!!!”

It’s as though the first character of the string is not being displayed. It’s in the byte array that’s being sent, but never makes it to the display.

I’ve got around it by adding a sacrificial character to the start of the string and that’s cured the problem, but it’s a nasty hack and I don’t like it!!!

I’ve got some refactoring to do in the code to use more constants, and most of the useful functionality is still to be added. I’m thinking I’ll put a Codeshare up when it’s finished too. Perhaps even create a new Gadgeteer module and library.

But, before I get ahead of myself any ideas why I’m seeing this behaviour?

Here’s the code with the extra character included “_”


using System;
using System.Collections;
using System.Threading;
using Microsoft.SPOT;
using Microsoft.SPOT.Presentation;
using Microsoft.SPOT.Presentation.Controls;
using Microsoft.SPOT.Presentation.Media;
using Microsoft.SPOT.Presentation.Shapes;
using Microsoft.SPOT.Touch;

using Gadgeteer.Networking;
using GT = Gadgeteer;
using GTM = Gadgeteer.Modules;
using Gadgeteer.Modules.GHIElectronics;
using Microsoft.SPOT.Hardware;
using System.Text;

namespace I2CLCD
{
    public partial class Program
    {
        int sleepTime = 100;

        private static byte SET_DDRAM_CMD = 0x80;
        private static byte DISP_CMD = 0x00;
        private static byte CLEAR_CMD = 0x01;

        // This method is run when the mainboard is powered up or reset.   
        void ProgramStarted()
        {
            Debug.Print("Program Started");
            DriveI2CLCD();

            Write("Hello World!!!");
        }

        private static I2CDevice I2C;
        private static I2CDevice.Configuration I2CConfig;

        private void DriveI2CLCD()
        {
            try
            {
                I2CConfig = new I2CDevice.Configuration(0x3E, 100);
                I2C = new I2CDevice(I2CConfig);

                var xActions = new I2CDevice.I2CTransaction[1];

                xActions[0] = I2CDevice.CreateWriteTransaction(new byte[] { 0x0, 0x38 });
                I2C.Execute(xActions, 1000);
                Thread.Sleep(sleepTime);

                xActions[0] = I2CDevice.CreateWriteTransaction(new byte[] { 0x0, 0x39 });
                I2C.Execute(xActions, 1000);
                Thread.Sleep(sleepTime);

                // Interna OSC Frequency
                xActions[0] = I2CDevice.CreateWriteTransaction(new byte[] { 0x0, 0x14 });
                I2C.Execute(xActions, 1000);
                Thread.Sleep(sleepTime);

                // Contrast Set
                xActions[0] = I2CDevice.CreateWriteTransaction(new byte[] { 0x0, 0x74 });
                I2C.Execute(xActions, 1000);
                Thread.Sleep(sleepTime);

                // Power
                xActions[0] = I2CDevice.CreateWriteTransaction(new byte[] { 0x0, 0x54 });
                I2C.Execute(xActions, 1000);
                Thread.Sleep(sleepTime);

                // Follower
                xActions[0] = I2CDevice.CreateWriteTransaction(new byte[] { 0x0, 0x6F });
                I2C.Execute(xActions, 1000);
                Thread.Sleep(sleepTime);

                // Display On/Off
                xActions[0] = I2CDevice.CreateWriteTransaction(new byte[] { 0x0, 0x0C });
                I2C.Execute(xActions, 1000);
                Thread.Sleep(sleepTime);

                // Clear Display
                xActions[0] = I2CDevice.CreateWriteTransaction(new byte[] { 0x0, 0x01 });
                I2C.Execute(xActions, 1000);
                Thread.Sleep(sleepTime);

            }
            catch(Exception ex)
            {
                Debug.Print(ex.Message);
            }
        }

        public void Write(string sText)
        {
            // Add sacraficial character here "_"
            sText = "_" + sText;

            var xActions = new I2CDevice.I2CTransaction[1];
            // Select position 0,0 (0x80)
            xActions[0] = I2CDevice.CreateWriteTransaction(new byte[] { DISP_CMD, SET_DDRAM_CMD });
            I2C.Execute(xActions, 1000);
            Thread.Sleep(sleepTime);

            // Encode the string
            byte[] buf = Encoding.UTF8.GetBytes(sText);                 // Convert the string to array
            // Create the xAction
            xActions[0] = I2CDevice.CreateWriteTransaction(buf);
            // Transmit the data
            I2C.Execute(xActions, 1000);
            // Wait
            Thread.Sleep(sleepTime);

        }

    }
}

This one for christmas? https://www.saleae.com/

1 Like

@ Jason : looks like you forget the initial 0x00 byte in the WriteTransaction when you send your text.

To me, your code should look like this (near the end) :


// Encode the string
byte[] buf = Encoding.UTF8.GetBytes((byte)0x00 + sText);                 // Convert the string to array
// Create the xAction
xActions[0] = I2CDevice.CreateWriteTransaction(buf);

Of course, you should then remove the sacrificial char :wink:

2 Likes

One thing that might be worth doing (not directly related to a missing character though) is wrap the I2C functions in error handling.

 if (MyI2C.Execute(xActions, 1000) == 0)
         {
             Debug.Print("Failed to perform I2C transaction");
         }
         else
         {
             Debug.Print("Register value: " + RegisterValue[0].ToString());
         }

One of the things that this data sheet doesn’t do well IMHO is talk about the I2C methodology. It explicitly shows a stream that starts with an I2C Start, the slave address, then a sequence of control byte plus data byte, repeated multiple times. So to test out what is going on, you could break your commands out into single data byte chunks to see if you don’t upset that stream, or if the way you’re doing the I2C transaction is actually ok. (they really could have made it a lot clearer!!)

1 Like

@ Bec a Fuel - I did some investigation on this but still couldn’t get it to work. I’ll try your example when I’ve some more time tomorrow and let you know.

@ Brett - Thanks for your thoughts. I’ll give this a try tomorrow.

So, after a little more time, and debugging this is what I ended up with.

Still some issues with the command set and dropping the first character, but I can work around that. Hope to develop it further to allow custom characters to be generated and used. Wish me luck.

Codeshare to follow.

1 Like

@ Bec a Fuel - Got it figured out with the help of some c code from Midas. Managed to add custom characters too. Thanks for your help. You were on the right tracks. I just needed the correct character to send.

Glad you’ve finally figured it out :clap:

That said, your Write() methods could be shorter by not involving a temporary array. Here’s an example for the Print(string text) method :

public void Print(string text)
        {
            byte[] buf = Encoding.UTF8.GetBytes(DATA_SEND + text);
            var xActions = new I2CDevice.I2CTransaction[1];
            xActions[0] = I2CDevice.CreateWriteTransaction(buf);
            I2C.Execute(xActions, 100);
        }

It could even be a one-liner, though less readable (but is it really important, here ?) :

public void Print(string text)
        {
            I2C.Execute(new I2CDevice.I2CTransaction[] { I2CDevice.CreateWriteTransaction(Encoding.UTF8.GetBytes(DATA_SEND + text)) }, 100);
        }

Anyway, you now have a working driver, that’s the most important thing.

2 Likes

@ Bec a Fuel - I tried this (or at least I think I did, first thing this morning and the byte that gets prepended to the string seemed to get messed up by the GetBytes(…) call. I try again now all is well with the code to see if I get the behaviour expected. I’ll let you know.