FRDM-KL25Z I2C rate

08 Jul 2013

Elsewhere on the forums /questions/802/Problem-with-I2C-read-commands/, someone pointed out a problem with the FRDM I2C implementation, and problems when the clock rate is > 100KHz. In a blog post MCU on Eclipse it was identified as a hardware bug where I2C only works correctly when the clock prescaler is set to 1.

There is also an errata on the freescale website, http://cache.freescale.com/files/microcontrollers/doc/errata/KINETIS_L_2N97F.pdf?fpsp=1 :

Quote:

e6070:I2C: Repeat start cannot be generated if the I2Cx_F[MULT] field is set to a non-zero value

Errata type: Errata

Description: If the I2Cx_F[MULT] field is written with a non-zero value, then a repeat start cannot be generated

Workaround: There are two possible workarounds:

1) Configure I2Cx_F[MULT] to zero if a repeat start has to be generated.

2) Temporarily set I2Cx_F [MULT] to zero immediately before setting the Repeat START bit in the I2C C1 register (I2Cx_C1[RSTA]=1) and restore the I2Cx_F [MULT] field to the original value after the repeated start has occurred

Is it possible to get a workaround into the MBED library? If I understand mcuoneclipse correctly, it is possible to achieve I2C clock rates by other methods, leaving the prescaler set to 1.

15 Jul 2013

I think I have a fix for this. The F[MULT] bits are set in the i2c_frequency() function in mbed-src/vendor/Freescale/KL25Z/hal/i2c_api.c. A minimal patch is:

<<verbatim>>
--- i2c_api.c   2013-07-11 02:05:47.306427939 +1000
+++ i2c_api.c.new       2013-07-11 02:08:55.737406031 +1000
@@ -198,7 +198,9 @@
     // we look for the values that minimize the error
 
     // test all the MULT values
-    for (i = 1; i < 5; i*=2) {
+    // ERRATA e6070: We require MULT = 0, otherwise repeated start doesn't work.
+    // for (i = 1; i < 5; i*=2) {
+    i = 1; {
         for (j = 0; j < 0x40; j++) {
             ref = PCLK / (i*ICR[j]);
             error = (ref > hz) ? ref - hz : hz - ref;
<</verbatim>>

That is, instead of testing all possible multipliers 1,2,4, only allow the multiplier to be 1 (corresponding to MULT=0). This appears to work OK.

Another improvement to this function would be to return the actual bus frequency that was chosen, or provide another function to calculate the current bus frequency.

14 Aug 2013

Hello,

thank you for reporting this issue. It was fixed by the mbed team, here's diff:

 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 < 100; i ++) __NOP();
+        obj->i2c->F |= temp << 6;
     } else {


Regards,
0xc0170