I2C on ublox C027 (LPC1768)

25 Nov 2015

I am trying to connect two ublox C027 boards via I2C. For that purpose I have soldered an adapter cable which connects the two boards' SCL and SDA pins, respectively, and pulls up each of them to 3.3V on one of the boards by a 2.2kOhm resistor.

I use the code below, and get the given output, which means to me that there is no communication between the two boards.

Have I missed something? What about the I2C classes' start and stop methods? Must they be called somewhere?

Common code

#include <string>
#include "mbed.h"
#include "C027_api.h"

DigitalOut led(LED);
const int slaveAddress = 0xA0;
const string successfully = "successfully";
const string unsuccessfully = "unsuccessfully";

string translateFailure(int failure) {
    return failure ? unsuccessfully : successfully;
}

Master code

int main() {
    c027_init();
    
    I2C i2cMaster(SDA, SCL);
    char count = 0;
    char read;
    int failure;
    while (true) {
        failure = i2cMaster.write(slaveAddress, &count, 1, false);
        printf("Master wrote '%d' %s.\n", count++, translateFailure(failure).c_str());
        led = !led;
        if (!failure) {
            failure = i2cMaster.read(slaveAddress, &read, 1, false);
            printf("Master read '%d' %s.\n", read, translateFailure(failure).c_str());
        }
        wait(1);
    }
}

Slave code

int main() {
    c027_init();
    printf("I2C slave pre-start...\n");
    
    I2CSlave i2cSlave(SDA, SCL);
    i2cSlave.address(slaveAddress);
    char count = 0;
    char read;
    int failure;
    while (true) {
        int status = i2cSlave.receive();
        switch (status) {
            case I2CSlave::NoData:
                printf("Slave received no data.\n");
                break;
            case I2CSlave::ReadAddressed:
                failure = i2cSlave.write(&count, 1);
                printf("Slave wrote '%d' %s.\n", count--, translateFailure(failure).c_str());
                break;
            case I2CSlave::WriteGeneral:
                failure = i2cSlave.read(&read, 1);
                printf("Read general message '%d' %s.\n", read, translateFailure(failure).c_str());
                break;
            case I2CSlave::WriteAddressed:
                failure = i2cSlave.read(&read, 1);
                printf("Read addressed message '%d' %s.\n", read, translateFailure(failure).c_str());
                break;
        }
    }
}

Master output

Master wrote '0' unsuccessfully.
Master wrote '1' unsuccessfully.
Master wrote '2' unsuccessfully.
Master wrote '3' unsuccessfully.
...

Slave output

I2C slave pre-start...
Slave received no data.
Slave received no data.
Slave received no data.
Slave received no data.
Slave received no data.
Slave received no data.
Slave received no data.
Slave received no data.
Slave received no data.
Slave received no data.
Slave received no data.
Slave received no data.
Slave received no data.
Slave received no data.
Slave received no data.
Slave received no data.
Slave received no data.
Slave received no data.
Slave received no data.
Slave received no data.
Slave received no data.
Slave received no data.
Read general message '0' successfully.
Slave received no data.
Slave received no data.
...

Thank you for your help.

25 Nov 2015

I dont have the C027, but have you made sure that both devices also have a common ground? Did you check the pins with a scope to make sure they are active when used as master (SDA, SCL transmission visible). Do they work as master when you address a hardware I2C slave (eg a PCF8574 portexpander). There seems to be one successful read for general address (ie address = 0x00). Any idea where that came from?

26 Nov 2015

Hi Wim,

thank you for the quick reply. The devices have common ground indeed. Our scope is at a former co-worker's, so I have to wait for a new one, which has already been ordered. I made a simple test with a voltmeter to check the pull-up resistors, but, of course, I don't see the actual signal shape that way. I'm using two of the C027s because we do not have other I2C hardware yet - I wanted to make sure that it really works before buying something, but I agree with you that it is probably better to test against a known working implementation. I have absolutely no idea where that read came from - it is reproducible after each reset of the slave if and only if the master is connected .

From your questions, I assume that my code seems alright. Would you agree? I was wondering anyway if there is a better way to poll the bus especially on the slave, maybe with an interrupt instead of an endless loop?

26 Nov 2015

Currently there is no general support for interrupt based I2C slaves (or masters) in the mbed libs. There is only some support for the Silicon Labs platforms. Also note that I2C slave code seems not well supported on many platforms. There may still be bugs in the C027 lib that cause your problems. It is strange that you receive General Address (address=0) with data (count) also 0. Maybe the bug somehow sets slaveaddress to 0 or to the count value. Is there any success message on the master side for this exchange?

You dont need the I2C start and stops in this case.

Test one step at a time, first a simple known good slave, check the traffic, then test master just writing one byte to I2Cslave receiver, then try two-way exchange. Its almost impossible to check I2C traffic without a logic analyser or memory scope. A regular scope is not able to actually capture the traffic, you can check clockspeed and maybe some repetitive messages and acks.

02 Dec 2015

Hi Wim,

we have an AD7998 eval board here, which has an I²C interface - it interacts with the C027 I²C master smoothly.