MKL02 I2C Master

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

MKL02 I2C Master

Jump to solution
4,802 Views
claeskjellstrom
Contributor III

Hi, I've been reading this forum for any answers regarding the behaviour of I2C bus and find allways different answers depending on who's responding. I hade a project where it ended up in such long time before production so I hade to change the bus to SPI and it didin't took long before that was working .Unfortunatelly I needed som devices that required I2C(crap) bus in a new project. In this case I use I2C1 bus and have only one device(VL53L1X) and the other channel(I2C0) I have a 24LC16 eeprom. Now it seems that the writing to the EEprom is working, but the reading is a mess since I simply don't understand the datasheet from Freescale and never has at least regarding the I2C. Below are the functions and I do not use interrupt for I2C.

bool I2C_ByteWrite(I2C_Type *base, uint8_t dev_adr, uint8_t reg_adr, uint8_t source)
{
if(I2C_Busy(I2C0))
{
i2c_start(base);
}
else
{
return(false);
}

if(!(I2C_WriteByte(base, (dev_adr + I2C_WRITE))))
{
return(false);
}
if(!(I2C_WriteByte(base, reg_adr)))
{
return(false);
}
if(!(I2C_WriteByte(base, source)))
{
return(false);
}

i2c_stop(base);

return(true);
}

and now the actually write function

bool I2C_WriteByte(I2C_Type *base, uint8_t data)
{
uint32_t timeout = 0U;

base->D = data;

while(!(base->S & I2C_S_IICIF_MASK))
{
if(timeout++ > I2C_TIMEOUT)
{
i2c.status |= I2C_TX_ERR;
return(false);
}
}

base->S |= I2C_S_IICIF_MASK;

timeout = 0U;

while(base->S & I2C_S_RXAK_MASK)
{
if(timeout++ > I2C_TIMEOUT)
{
i2c.status |= I2C_NO_ACK;
return(false);
}
}
return(true);
}

Here is the read function

bool I2C_ByteRead(I2C_Type *base, uint8_t dev_adr, uint8_t reg_adr, uint8_t *dest)
{
if(I2C_Busy(I2C0))
{
i2c_start(base);
}
else
{
return(false);
}

if(!(I2C_WriteByte(base, (dev_adr + I2C_WRITE))))
{
return(false);
}
if(!(I2C_WriteByte(base, reg_adr)))
{
return(false);
}

i2c_repeated_start(base);

if(!(I2C_WriteByte(base, (dev_adr + I2C_READ))))
{
return(false);
}

i2c_set_rx_mode(I2C0);

if(!(I2C_ReadByte(base, &dummy, _ACK)))
{
return(false);
}

if(!(I2C_ReadByte(base, dest, _NACK)))
{
return(false);
}

i2c_stop(base);

return(true);
}

and now the actually read function

bool I2C_ReadByte(I2C_Type *base, uint8_t *dest, bool ack)
{
// uint32_t timeout = 0U;
dest[0U] = base->D;

if(ack)
{
base->C1 |= I2C_C1_TXAK_MASK;
}
else
{
base->C1 &=~I2C_C1_TXAK_MASK;
}

/* while(!(base->S & I2C_S_IICIF_MASK))
{
if(timeout++ > I2C_TIMEOUT)
{
i2c.status |= I2C_RX_ERR;
return(false);
}
}
*/
base->S |= I2C_S_IICIF_MASK;

return(true);
}

I have changed the read function a million times and the problem allways come with a dummy read becaus I don't have any control over the received byte.

The oscilloscope picture's which I haven't attached is correct for writing but when switching over rx mode and reading the dummy byte or even the last byte(NACK) I allways get 0xFF.

I have even tryed with some modification the KL05 I2C driver but that caused me to com up with a recovery solution whe I2C got stucked. I do have pullups(4K7) and I'm running at 100KHz.

Regards

Claes 

0 Kudos
1 Solution
4,321 Views
claeskjellstrom
Contributor III

Hi,

1.Yes correct

2.When a stop is issued this must be wrong then:

base->C1 &=~(I2C_C1_IICIE_MASK | I2C_C1_IICEN_MASK | I2C_C1_MST_MASK | I2C_C1_TX_MASK);

Regards

Claes

View solution in original post

0 Kudos
31 Replies
1,364 Views
claeskjellstrom
Contributor III

Hi Mark,

In my desperation I was adding a check on TCF flag before checking and clear IICIF flag. That didn't help but what happend was that SCL started to completly uncontrolled oscillate at a high frequence(12MHz)

and SDA line low. Now it's impossible to send a START condition because both SCL and SDA remains high. I only have the eep as a slave on I2C0. Any suggestions(alcohol, pills, smoke), or can someone implement code if I attache it.

/Claes

 

0 Kudos
1,414 Views
claeskjellstrom
Contributor III

I'm attached the code

/Claes

0 Kudos
1,414 Views
claeskjellstrom
Contributor III

I forgott to mention that the data 0x35 that is written is allways 0xFF when reading.

/Claes

0 Kudos
1,410 Views
mjbcswitzerland
Specialist V

Hi

Looking at the scope shot I see that the 0x35 that is written is not acked but all acks up to that point were OK.
Is it possible that you are sending the STOP condition too early and then sending further commands too? It is not easy to see from a scope shot but it looks like there may be more that 9 clocks being generated by the master during the final burst which points to the master continuing with further activity before the previous had terminated.

Regards

Mark
[uTasker project developer for Kinetis and i.MX RT]
Contact me by personal message or on the uTasker web site to discuss professional training, solutions to problems or product development requirements

 

0 Kudos
1,391 Views
claeskjellstrom
Contributor III

Hi,

I have to buy a simple logic analizer, it's difficult to see details unless zooming the scope but then you miss the entire transmission. I'll be back.

Claes

0 Kudos
1,362 Views
claeskjellstrom
Contributor III

Hi Mark,

Bought  a SP209 logic analyser, and found a simple fault in code, which means that I'm still trying to understand why everything looks fine according the analyser both for Read and Write, but nothing has been written to eep. However I decided to further write code with interrupt so I have split read and write in states. I do have a question regarding Read and Restart. The Restart itself does not generate a new interrupt or ?

Regards

Claes

 


if(eep.rd_wr == I2C_READ)
{
   if(eep.state == DEVICE_ADDRESS)
   {
     eep.state = REGISTER_ADDRESS;
     I2C0->D = eep.reg_adr;
   }
   else if(eep.state == REGISTER_ADDRESS)
   {
     eep.state = RESTART;
     i2c_repeated_start(I2C0);
   }
   else if(eep.state == RESTART)
   {
      eep.state = SW_READ_DATA;
      I2C0->D = (eep.dev_adr | I2C_READ);
   }
   else if(eep.state == SW_READ_DATA)
   {

0 Kudos
1,358 Views
mjbcswitzerland
Specialist V

Hi

The I2C master doesn't generate an interrupt after it has sent a start or repeated start condition - it interrupts only after the address has been sent. See page 17 of https://www.utasker.com/docs/uTasker/uTasker_I2C.pdf for the I2C flag operation.

This is however I2C type dependent since some Kinetis parts (like KL27) with double buffered I2C type can generate interrupts after sending a repeated start and it is also necessary to handle this in order to correctly send the slave address.

Some other Kinetis parts have an alternative low power I2C (LPI2C) which is more autonomous and again has different rules to follow.

Regards

Mark

0 Kudos
1,353 Views
claeskjellstrom
Contributor III

Hi,

I now have two I2C routines, blocking and none blocking, They create same outcome, and as you asked Mark, a couple of mails ago, if there is a writeprotection and answer is still the WP pin is grounded. Now that I have a logic analyser it all look perfect, and still writing is not changing the memory contents.Program starts with reading 16bytes and if unprogrammed it write's 16 bytes starting at adress 0x00(value 0x01) to address 0x0F(value 0x10) . the output file *.csv from sp209 could not be attached here.

/Claes

0 Kudos
1,338 Views
claeskjellstrom
Contributor III

Mark,

I have attached the file(*.rar 6Kbytes) from scanaStudio where the whole sequence can be seen.

Reading 16bytes from block-1 at address 0, then writing 8bytes(value 1,2.....8) starting from address 0 ,block-1. WP,A0,A1,A2=ground, VCC 3.0Vdc, Pullup 3K3 SDA,SCL. baudrate ~250KHz.

The device address+block-1 should be 0xA2(with scanastudio since its 7bit representation the address is 0x51). If you have the time, please try to look at it.

Regards

Claes

0 Kudos
1,335 Views
mjbcswitzerland
Specialist V

Hi

From the I2C recording I see two things:
1. When you read 16 bytes the final byte is still acked - this should not be acked in order to signal to the slave that all data has been read.

2. There is no stop condition at the end of the data write.
I think that it is the stop condition that triggers the write inside the EEPROM and so without it it will probably never be programming anything.

Regards

Mark

 

0 Kudos
4,322 Views
claeskjellstrom
Contributor III

Hi,

1.Yes correct

2.When a stop is issued this must be wrong then:

base->C1 &=~(I2C_C1_IICIE_MASK | I2C_C1_IICEN_MASK | I2C_C1_MST_MASK | I2C_C1_TX_MASK);

Regards

Claes

0 Kudos