10 years, 9 months ago.

What changed in mbed v63 of i2c (master mode) for the KL25Z ?

I just updated my mbed code for program KL25Z_MLX90620 from v62 to v64 and the i2c code stopped working. I pushed back to v63 and it was still broken. Pushed back to v62 and everything works again.

What changed?

thanks,

...kevin

1 Answer

10 years, 8 months ago.

Hi,

Have you tried to find out where does your code break with v63/v64?

Thanks,

Bogdan

EDIT: one more thing: does the problem go away if you run the interface at 100KHz instead of 400KHz?

EDIT2: I created a repository with a tentative fix here:

http://mbed.org/users/bogdanm/code/kl25z-i2c-fix/

Please let me know if it fixes the problem for you (this should work at 400KHz).

EDIT3: I'm having intermitent results with my fix; if it still doesn't work for you, try adding a small delay after the repeated start. Something like below:

        temp = obj->i2c->F >> 6;
        obj->i2c->F &= 0x3F;
        obj->i2c->C1 |= 0x04;
        for (i = 0; i < 100; i ++) __NOP();
        obj->i2c->F |= temp << 6;

Hi Bogdan,

EDIT: no, changing to 100KHz does not fix my problem.

EDIT2: Do you have an example on how to use your library?

EDIT3: I am using the higher level i2c commands. Example below:

unsigned short MLX90620::GetOscTrimReg() { 
    RamCmmd[0] = 2;                          //command
    RamCmmd[1] = MLXTRIM;                    //address of register
    RamCmmd[2] = 0;                          //address step
    RamCmmd[3] = 1;                          //# of reads
    _i2c.write(0xc0, RamCmmd, 4, true);  
    _i2c.read(0xc0, RamCmmd, 2);
    OscTrim = (RamCmmd[1] << 8) + RamCmmd[0];
    return(OscTrim);
}

EDIT3a. How would I insert the delay into the example above?

EDIT3b. Can I use a simple wait_us(100) instead of for (i = 0; i < 100; i ++) NOP(); ?

...kevin

posted by Kevin Braun 06 Aug 2013

Hi again Bogdan,

EDIT2: For grins, I imported your fix library, but made no references to it. I get a compiler error

""/extras/mbed_e3affc9e7238/TARGET_KL25Z/TOOLCHAIN_ARM_STD/MKL25Z4.sct", line 4 (column 9): Error: L6235E: More than one section matches selector - cannot all be FIRST/LAST." in file "/"

Cheers,

...kevin

posted by Kevin Braun 06 Aug 2013

I can answer that one at least. His library is a modified version of mbed-src. So delete your current mbed library, import his library.

posted by Erik - 06 Aug 2013

Thanks Erik - that was easy,

Bogden,

I tried the library change, but there was no change in behavior.

...kevin

posted by Kevin Braun 06 Aug 2013

Thanks for your feedback. Did you try with the delay, but without the for, just as you suggested (wait_us(100)) ? The delay that I suggested is in the library code itself (function i2c_start in my library, file targets/hal/TARGET_Freescale/TARGET_KL25Z/i2c_api.c). Modify that function to look like this:

int i2c_start(i2c_t *obj) {
    uint8_t temp;
    volatile int i;
    // if we are in the middle of a transaction
    // activate the repeat_start flag
    if (obj->i2c->S & I2C_S_BUSY_MASK) {
        // KL25Z errata sheet: repeat start cannot be generated if the I2Cx_F[MULT] field is set to a non-zero value
        temp = obj->i2c->F >> 6;
        obj->i2c->F &= 0x3F;
        obj->i2c->C1 |= 0x04;
        for (i = 0; i < 200; i ++) __NOP();
        obj->i2c->F |= temp << 6;
    } else {
        obj->i2c->C1 |= I2C_C1_MST_MASK;
        obj->i2c->C1 |= I2C_C1_TX_MASK;
    }
    first_read = 1;
    return 0;
}

(notice the additional 'for' loop in the function which provides the delay).

posted by Bogdan Marinescu 06 Aug 2013

What goes in to (i2c_t *obj) ?

posted by Kevin Braun 06 Aug 2013

That's the internal representation of the I2C interface. You shouldn't worry about that, the high level code (common/I2C.cpp) hides the HAl details from your code. Or maybe I didn't understand your question?

EDIT: by the way, you can simply update to my latest version of the code, compile and retry. I added the code for the wait in i2c_api.c on KL25Z.

posted by Bogdan Marinescu 06 Aug 2013

It must need something. The compiler complains that there are too few arguments.

I'll try your latest update. I'll need a few minutes

posted by Kevin Braun 06 Aug 2013

That is very weird. Could you please post the full error report?

posted by Bogdan Marinescu 06 Aug 2013

I tried the latest kl25z-i2c-fix v16. No change. I'll go back to patching in the delay

posted by Kevin Braun 06 Aug 2013

This is the only error:

"Too few arguments in function call" in file "MLX90620MLX90620.cpp", Line: 88, Col: 1

line 88 is:

i2c_start_fix(); I had to add "_fix" to the name because i2c_start already exists.

int first_read = 0;

int i2c_start_fix(i2c_t *obj) {
    uint8_t temp;
    volatile int i;
    // if we are in the middle of a transaction
    // activate the repeat_start flag
    if (obj->i2c->S & I2C_S_BUSY_MASK) {
        // KL25Z errata sheet: repeat start cannot be generated if the I2Cx_F[MULT] field is set to a non-zero value
        temp = obj->i2c->F >> 6;
        obj->i2c->F &= 0x3F;
        obj->i2c->C1 |= 0x04;
        for (i = 0; i < 200; i ++) __NOP();
        obj->i2c->F |= temp << 6;
    } else {
        obj->i2c->C1 |= I2C_C1_MST_MASK;
        obj->i2c->C1 |= I2C_C1_TX_MASK;
    }
    first_read = 1;
    return 0;
}

The calling routine (in progress)

int MLX90620::LoadEEPROM() {
    //clear out buffer first
    for(int i = 0; i < 256; i++) {
        EEbuf[i] = 0;
    }
    
    //load the entire EEPROM
    EEbuf[0] = 0;
    if(!_i2c.write(0xa0, EEbuf, 1, true)) {                //0 returned is ok
        i2c_start_fix();
        _i2c.write(0xa1);
        for(int i = 0; i < 256; i++) {
            EEbuf[i] = _i2c.read(1);
        }
//        _i2c.read(0xa0, EEbuf, 256);                       //load contents of EEPROM
    } else {
        _i2c.stop();
        return(1);
    }
    _i2c.stop();
    return(0);
}

Line 10 in the calling routine is line 88 as far as the compiler is concerned

posted by Kevin Braun 06 Aug 2013

Again, no need to do that. Just update to my latest revision of the library and test it with your original code. My suggestion was to modify the i2c_api.c file that I've been talking about, not to add another function to your own code. In short:

1. update to my latest version of the code 2. test it with your _unmodified_ code 3. let me know if that works :)

HTH,

Bogdan

posted by Bogdan Marinescu 06 Aug 2013

I did that. See my reply just before this latest one. There was no change in behavior

posted by Kevin Braun 06 Aug 2013

Sorry, I haven't seen that. Could you please give me more information on the error? What exactly do you mean by "the I2C code stopped working"?

posted by Bogdan Marinescu 06 Aug 2013

See private message Bogdan

posted by Kevin Braun 06 Aug 2013