I2C Problem (Mcp23017)


Recommended Posts

I have been having some trouble trying to get my MCP23017 I2C chip to work with an U3-LV LabJack.

I am using DAQFactory's scripting language and I am trying to simply write a value of 0-255 to the I2C chip to use it with a multiplexer basically as an expanded I/O.

 

 

Using an oscilloscope, for SCL I got a square wave at 20kHz that lasted 10 cycles. 

Also no matter how I change the array or the values to write the SDA(data) signal looks exactly the same. It looks like this starting from High(~5V); 20 microseconds Low, 10 microseconds High, 60 microseconds Low, 15 microseconds High, 10 microseconds Low, back to High. The falling edge for that was about 100-200 nanoseconds.

 

Using LJ Control Panel I have verified that it is connecting to my computer and that the pins work like they should for Analog/Digital Setups.

 

 

Here is my code:

using("device.labjack.")
include("C:\Program Files\LabJack\Drivers\LabJackud.h")

AddRequest(0, LJ_ioPUT_CONFIG, LJ_chI2C_ADDRESSBYTE, 64, 0, 0)
AddRequest(0, LJ_ioPUT_CONFIG, LJ_chI2C_SCL_PIN_NUM, 3, 0, 0)
AddRequest(0, LJ_ioPUT_CONFIG, LJ_chI2C_SDA_PIN_NUM, 4, 0, 0)
AddRequest(0, LJ_ioPUT_CONFIG, LJ_chI2C_OPTIONS, 4, 0, 0)
AddRequest(0, LJ_ioPUT_CONFIG, LJ_chI2C_SPEED_ADJUST, 0, 0, 0)

GoOne(0)


numWrite = 2
array[0] = 19
array[1] = 255

AddRequest(0, ioI2C_COMMUNICATION, LJ_chI2C_WRITE, numWrite, array, 0)

GoOne(0)

I have tried instead of an array splitting it into 2 parts and I have tweaked various configurations.

 

Here is the datasheet:

http://www.mouser.com/ds/2/268/21952b-70868.pdf

 

 

 

Thanks in advance,

David

 

Link to comment
Share on other sites

This was resolved in email support. Resolution below:

 

 

First power cycle the chip so that it's register mapping is reset.
 
Then configure the IO directions by writing: address = 0x40, Data0 = 0x00 (select the IODIRA register), Data1 = 0x00 (Set all lines on bank A to output.)
 

Then we can write the output latches: address = 0x40, Data0 = 0x14 (select the OLATA register), Data1 = 0x55 (test pattern).

Link to comment
Share on other sites

  • 1 year later...

I'm trying to do the exact same thing.  I'm using NI CVI to try and get the all of the MCP23017 DIO pins to all go high.  I have the following code without much luck:

//MCP address is 0x20 or 32 in deci and is connected to pin 16 and 17 CIO0 and CIO1

    lngErrorcode = AddRequest(lngHandle, LJ_ioPUT_CONFIG, LJ_chI2C_ADDRESS_BYTE,32,0,0);
    lngErrorcode = AddRequest(lngHandle, LJ_ioPUT_CONFIG, LJ_chI2C_SCL_PIN_NUM,16,0,0);
    lngErrorcode = AddRequest(lngHandle, LJ_ioPUT_CONFIG, LJ_chI2C_SDA_PIN_NUM,17,0,0);
    lngErrorcode = AddRequest(lngHandle, LJ_ioPUT_CONFIG, LJ_chI2C_OPTIONS,4,0,0);
    lngErrorcode = AddRequest(lngHandle, LJ_ioPUT_CONFIG, LJ_chI2C_SPEED_ADJUST,0,0,0);
    lngErrorcode = GoOne(lngHandle);

    //set direction
    numI2CBytesToWrite = 2;
    writeArray[0] = 0;  //Memory address.  DIRA 0x00
    writeArray[1] = 0;  // set the MCP23017 I/O pins to outputs
    lngErrorcode = AddRequest(lngHandle, LJ_ioI2C_COMMUNICATION, LJ_chI2C_WRITE, numI2CBytesToWrite, pwriteArray, 0);

    writeArray[0] = 1;  //Memory address.  DIRB 0x01
    writeArray[1] = 0;  // set the MCP23017 I/O pins to outputs
    lngErrorcode = AddRequest(lngHandle, LJ_ioI2C_COMMUNICATION, LJ_chI2C_WRITE, numI2CBytesToWrite, pwriteArray, 0);

    writeArray[0] = 18;  //Memory address.  0x12
    writeArray[1] = 255;  // set the MCP23017 I/O pins to outputs    
    lngErrorcode = AddRequest(lngHandle, LJ_ioI2C_COMMUNICATION, LJ_chI2C_WRITE, numI2CBytesToWrite, pwriteArray, 0);

    writeArray[0] = 19;  //Memory address. 0x13  
    writeArray[1] = 255;  // set the MCP23017 I/O pins to outputs  
    lngErrorcode = AddRequest(lngHandle, LJ_ioI2C_COMMUNICATION, LJ_chI2C_WRITE, numI2CBytesToWrite, pwriteArray, 0);
    lngErrorcode = GoOne(lngHandle);  

 

There are no errors, but all of the GPIOs are still low.

 

Link to comment
Share on other sites

There are a few things that are probably wrong with your code so I am going to point you to an example library we have slowly been working on to hopefully help you understand what the driver/device is doing and then suggest fixes to your code.  This example code is for Matlab but it is still fairly useful as the naming still follows the AddRequest and GoOne format.
https://github.com/labjack/I2C-AppNotes/blob/master/UD_Driver/I2C_Abstraction_Layers/matlab/UD_I2C_Utils.m

You should also look at the I2C application note on our website:
https://labjack.com/support/app-notes/i2c

To perform I2C Operations, you should follow one of the functions, several are defined (you can search for these names in the .m file):
read
readAndGetAcks
write
writeAndGetAcks
writeAndRead
writeGetAcksAndRead

There is also one "configure" function that describes what the configurations do.  Your code that has multiple "AddRequest" commands and then a "GoOne" command will be slightly more efficient in terms of device I/O as all of the device communications happen when you execute the "GoOne" command.  The matlab example uses "ePut" commands that perform device I/O immediately.

To summarize what all of the I2C operation functions are doing, they:
1. Do some matlab-stuff for defining and populating arrays.
2. Prepare for an I2C operation by adding a "read" or "write" request.  I don't believe you can have multiple write requests stacked up in a row but this might be ok.  When getting started I suggest only doing one combination of a single read, a single write, or a write followed by a read.  
3. Some of the functions tell the device to keep track of the "ack" bits received from the sensor.  I recommend doing this when getting started, you want to make sure this number isn't zero.  If it is then you are likely not communicating with the correct slave address or the pull-up resistors on the SDA and SCL lines are either missing or to large/small.
4. Execute the "GoOne" command which tells the device to perform the I2C operation.  
5. If required, (when reading data, or checking the number of received acks) read data.

Moving on to your specific sensor and supplied code, depending on how you have configured the I2C slave address jumper lines, you need to shift your slave address over by one bit when using the UD driver/U3/U6/UE9 devices.  The T7 is different (look at the LJM version of this wrapper in the same .git repo).  The UD driver requires a "shifted 7-bit slave address".  The UD driver automatically toggles the lowest bit (the read/write bit) to indicate read/write I2C commands.  It doesn't automatically shift the 7-bit slave address.  You should try writing 32<<1 or 0x20<<1.  It looks like this is what "winterv" was doing.

You should also add "GoOne" commands in between all of your I2C write commands.  

Make sure you have installed 4.7k resistors between VS and the SDA/SCL lines.

If this doesn't work we (LabJack) highly recommend that you pick up a logic analyzer (you can get them for pretty cheap), they are very useful for debugging digital communication issues.  Most have I2C/SPI/UART/1-Wire data interpreters that let you see what data is being written to/read from your connected sensor.  

Link to comment
Share on other sites

Thank you so much for your support and fast response!

I have modified my code per your example and have tried the ePut and addRequest methods.  I've also verified that all the address bits are tied low that correspond with address 0x20, which corresponds to 32 and becomes 64 when bit shifted.  There is also an identical chip on the board with address 0x21 where A0 is high and it behaves the same.  I have also confirmed that I have 2kohm pull up on all data lines.  I also used a logic analyzer to confirm that all 4 of my writes are being transmitted correctly and probed the SCL and SDA on the target chip itself.  

i2c.PNG

Here is the first zoomed in transmission.  The trace below shows the correct address 0100000 = 64 and then a 0 for write.  The data is also correct.

i2c_zoom.PNG

The logic analyzer provides a simulation of a typical i2c transmission:i2c_simulation.PNG

It is showing a 9th clock, which is the ack/nak.  Low for ack and high for nak.  But on my trace, the 9th clock is longer and is continuous until the next data cycle unlike in the example. Not sure if that is a problem.  In either case, the data line is showing a NAK each time.

The result agrees with the trace: that when I read back the ACKs, it is 0 and the DIOs do not go high.  My code is below:

    lngErrorcode = ePut(lngHandle, LJ_ioPUT_CONFIG, LJ_chI2C_ADDRESS_BYTE,64,0);          
    lngErrorcode = ePut(lngHandle, LJ_ioPUT_CONFIG, LJ_chI2C_SCL_PIN_NUM,16,0);
    lngErrorcode = ePut(lngHandle, LJ_ioPUT_CONFIG, LJ_chI2C_SDA_PIN_NUM,17,0);
    lngErrorcode = ePut(lngHandle, LJ_ioPUT_CONFIG, LJ_chI2C_OPTIONS,0,0);
    lngErrorcode = ePut(lngHandle, LJ_ioPUT_CONFIG, LJ_chI2C_SPEED_ADJUST,0,0);    
    
    numI2CBytesToWrite = 2;
    writeArray[0] = 0;  //Memory address.  DIRA 0x00 
    writeArray[1] = 0;  // set the MCP23017 I/O pins to outputs
    lngErrorcode = AddRequest(lngHandle, LJ_ioI2C_COMMUNICATION, LJ_chI2C_WRITE, numI2CBytesToWrite, pwriteArray, 0);    
    lngErrorcode = AddRequest(lngHandle, LJ_ioI2C_COMMUNICATION, LJ_chI2C_GET_ACKS, 0, 0, 0);
    lngErrorcode = GoOne(lngHandle);    
    lngErrorcode = GetResult(lngHandle, LJ_ioI2C_COMMUNICATION, LJ_chI2C_GET_ACKS, &writeACKS);              

    writeArray[0] = 1;  //Memory address.  DIRA 0x01
    writeArray[1] = 0;  // set the MCP23017 I/O pins to outputs
    lngErrorcode = AddRequest(lngHandle, LJ_ioI2C_COMMUNICATION, LJ_chI2C_WRITE, numI2CBytesToWrite, pwriteArray, 0);
    lngErrorcode = AddRequest(lngHandle, LJ_ioI2C_COMMUNICATION, LJ_chI2C_GET_ACKS, 0, 0, 0);
    lngErrorcode = GoOne(lngHandle);    
    lngErrorcode = GetResult(lngHandle, LJ_ioI2C_COMMUNICATION, LJ_chI2C_GET_ACKS, &writeACKS);      
    
    writeArray[0] = 18; //memory address is 0x12  
    writeArray[1] = 255;  // set the MCP23017 I/O pins to outputs    
    lngErrorcode = AddRequest(lngHandle, LJ_ioI2C_COMMUNICATION, LJ_chI2C_WRITE, numI2CBytesToWrite, pwriteArray, 0);    
    lngErrorcode = AddRequest(lngHandle, LJ_ioI2C_COMMUNICATION, LJ_chI2C_GET_ACKS, 0, 0, 0);
    lngErrorcode = GoOne(lngHandle);    
    lngErrorcode = GetResult(lngHandle, LJ_ioI2C_COMMUNICATION, LJ_chI2C_GET_ACKS, &writeACKS);              
    
    writeArray[0] = 19; //memory address is 0x13
    writeArray[1] = 255;  // set the MCP23017 I/O pins to outputs    
    lngErrorcode = AddRequest(lngHandle, LJ_ioI2C_COMMUNICATION, LJ_chI2C_WRITE, numI2CBytesToWrite, pwriteArray, 0);
    lngErrorcode = AddRequest(lngHandle, LJ_ioI2C_COMMUNICATION, LJ_chI2C_GET_ACKS, 0, 0, 0);
    lngErrorcode = GoOne(lngHandle);    
    lngErrorcode = GetResult(lngHandle, LJ_ioI2C_COMMUNICATION, LJ_chI2C_GET_ACKS, &writeACKS);    

 

<Solved Update>  This has been a very good exercise, but I figured out that the problem I had was that my SCL and SDA lines were switched.  I am now getting the correct number of ACKs back and the DIO pins are high.  Thanks so much for your support!
 

Link to comment
Share on other sites

Archived

This topic is now archived and is closed to further replies.