10 years, 11 months ago.

Can't read I2C data on FRDM-KL25Z

Hi, I'm trying to use the read function on I2C on the FRDM-KL25Z, but can't get any SCL pulses from the read command. Works fine on the LPC1768. See screen shots:-

/media/uploads/PhilG1300/screen_shot_2013-04-09_at_17.03.12.png

On the LPC1768:-

/media/uploads/PhilG1300/screen_shot_2013-04-09_at_17.07.32.png

My code is shown below:-

  1. include "mbed.h"

DigitalOut myled(LED1); I2C bmp(PTE0, PTE1); I2C bmp(p28, p27);

int main() { int i; int data[2]; wait(5); myled = 1; bmp.frequency(100000); bmp.start(); bmp.write(0xA0); bmp.write(0x00); bmp.write(0x00); bmp.start(); bmp.write(0xA1); i = bmp.read(0); bmp.stop();

while(1) { myled = 1; wait(0.2); myled = 0; wait(0.2); } }

Any suggestions? Regards Phil.

1 Answer

10 years, 11 months ago.

Please use <<code>> and <</code>> around your code to improve readability.

Took me quite some searching around in source code, especially since I believe others also had problems with I2C. The short answer: just use the complete reading/writing functions, that is way easier also. So something like:

int address = 0xA0;
char data[] = {0, 0};
char received_data;
bmp.write(address, data, 2, true);
bmp.read(address, &received_data, 1);

The longer answer: the mbed code for single byte reading on the KL25Z appears to me to be broken (feel free to also report that in the bug forum). Doing a single byte read is done by calling the i2c_byte_read C function, which is defined as:

int i2c_byte_read(i2c_t *obj, int last) {
    char data;
    i2c_do_read(obj, &data, last);
    return data;
}

So that simply consists of the i2c_do_read function being called. All nice and we lived happily ever after. However, the i2c_do_read function is only half a function:

static int i2c_do_read(i2c_t *obj, char * data, int last) {
    if (last)
        i2c_send_nack(obj);
    else
        i2c_send_ack(obj);
 
    *data = (obj->i2c->D & 0xFF);
 
    // start rx transfer and wait the end of the transfer
    return i2c_wait_end_rx_transfer(obj);
}

This one took me a bit to figure out. It first either sets or removes the ACK bit. Makes sense. However then it reads from the I2C register, even though it hasn't started transfer yet. And then it waits till the transfer is complete, even though we already read the data. But with a bit of looking through the reference manual and later the other read function (the one I used in the beginning here, which does appear to be functional), it slowly started to make sense.

The first read is a dummy read. The other read function simply throws away the data that comes from that. This is only used to initiate the read process. I still don't really get how the ACK/NACK stuff works, if it isn't set correctly the KL25 will keep the SCL line low, which is exactly what you see. However I am fairly certain also the other read function doesn't work when it ends with a repeated start condition: according to the datasheet you should put it in TX mode before initiating your last read to the data register, otherwise it will initiate yet another read. The mbed code doesn't do this. If it ends with a stop condition it will put the peripheral in slave mode, that should also prevent starting another master receive cycle. However when it doesn't end in a stop condition this won't work either most likely.

But without either a Freescale board or a logic analyzer I can't test all that myself :P

Btw @ mbed guys, checking after every do_read if the function returns the expected 0 is nice, but you do know that function is hardcoded to return 0?

Erik,

I am trying to patch the code above into a driver. Where is i2c_send_nack(obj); i2c_send_ack(obj); i2c_wait_end_rx_transfer(obj); defined?

...kevin

posted by Kevin Braun 24 Jul 2013

Kevin,

That code is defined here: http://mbed.org/users/mbed_official/code/mbed-src/file/5fa2273de5db/vendor/Freescale/KL25Z/hal/i2c_api.c.

However this bug was quietly patched by the mbed guys, so you should just be able to use the normal functions.

posted by Erik - 24 Jul 2013

Thanks Erik

posted by Kevin Braun 25 Jul 2013