MKL02 I2C Master

キャンセル
次の結果を表示 
表示  限定  | 次の代わりに検索 
もしかして: 
7,756件の閲覧回数
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 件の賞賛
返信
1 解決策
7,275件の閲覧回数
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 件の賞賛
返信
31 返答(返信)
5,059件の閲覧回数
claeskjellstrom
Contributor III

Hi, I will continue this monolouge.

By reading Freescales flow diagram and comparing other solution for single read byte on I2C they seem to be roughly the same code with some minor changes. However it's difficult to understand that the real last byte to read is after a stop condition. As I see it when you make a stop then the result in the D-register is cleared so I will never catch that byte.

Any suggestions ?? I have copied some code from other examples below

unsigned char I2C_ReadRegister(unsigned char u8SlaveAddress, unsigned char u8RegisterAddress)
{
unsigned char result;

I2C_Start();
I2C0_D = u8SlaveAddress << 1; /* Send I2C device address with W/R bit = 0 */
I2C_Wait();

I2C0_D = u8RegisterAddress; /* Send register address */
I2C_Wait();

I2C_RepeatedStart();

I2C0_D = (u8SlaveAddress << 1) | 0x01; /* Send I2C device address this time with W/R bit = 1 */
I2C_Wait();

I2C_EnterRxMode();
I2C_DisableAck();

result = I2C0_D;
I2C_Wait();
I2C_Stop();
result = I2C0_D;
Pause(50);
return result;

 

or

/* Put in Rx Mode */
I2C_C1_REG(i2cbus) &= (~I2C_C1_TX_MASK);

/* Dummy read */
result = I2C_D_REG(i2cbus) ;
if(1 == len)
/* Turn off ACK */
I2C_C1_REG(i2cbus) |= I2C_C1_TXAK_MASK;
else
I2C_C1_REG(i2cbus) &= ~I2C_C1_TXAK_MASK;

while (len--) {
i2c_Wait(i2cbus);
if (len != 0) {
if (len == 1)
I2C_C1_REG(i2cbus) |= I2C_C1_TXAK_MASK;
}
else {
i2c_Stop(i2cbus);
I2C_C1_REG(i2cbus) &= ~I2C_C1_TXAK_MASK;
}
/* Read byte */
result = I2C_D_REG(i2cbus) ;
*u8Data++ = result;
}
ret = 0;
Pause();
return ret;

 

or

 

/* Put in Rx Mode */


I2C0_C1 &= (~I2C_C1_TX_MASK);

 

/* Ensure TXAK bit is 0 */


I2C0_C1 &= ~I2C_C1_TXAK_MASK;

 

/* Dummy read */


result[0] = I2C0_D ;


i2c_Wait();

 

for(i=0;i<n-2;i++)


{


/* Read first byte */


result[i] = I2C0_D;


i2c_Wait();


}


/* Turn off ACK since this is second to last read*/


I2C0_C1 |= I2C_C1_TXAK_MASK;

 

/* Read second byte */


result[i++] = I2C0_D;


i2c_Wait();

 

/* Send stop */

 

0 件の賞賛
返信
5,051件の閲覧回数
mjbcswitzerland
Specialist V

Hi

You can get an I2C solution for the KL02 at https://github.com/uTasker/uTasker-Kinetis

User's guide: https://www.utasker.com/docs/uTasker/uTasker_I2C.pdf

Here is a non-interrupt read from a 24C01:

 

int iReadCnt = 0;
int iToRead = 10;
unsigned char ucAddressToReadFrom = 0;
unsigned char ucReadBuffer[10];
KINETIS_I2C_CONTROL *ptrI2C;
POWER_UP_ATOMIC(4, I2C0);                                        // enable clock to module
_CONFIG_PERIPHERAL(B, 4,  (PB_4_I2C0_SDA | PORT_ODE | PORT_PS_UP_ENABLE)); // I2C0_SDA on PB4 (alt. function 2)
_CONFIG_PERIPHERAL(B, 3,  (PB_3_I2C0_SCL | PORT_ODE | PORT_PS_UP_ENABLE)); // I2C0_SCL on PB3 (alt. function 2)
ptrI2C = (KINETIS_I2C_CONTROL *)I2C0_BLOCK;
ptrI2C->I2C_F = 0x28;                                            // set the operating speed
ptrI2C->I2C_C1 = (I2C_IEN);                                      // enable I2C controller

ptrI2C->I2C_C1 = (I2C_IEN | I2C_IIEN | I2C_MTX);                 // set transmit mode with interrupt enabled
ptrI2C->I2C_C1 = (I2C_IEN | I2C_IIEN | I2C_MSTA | I2C_MTX);      // set master mode to cause start condition to be sent
ptrI2C->I2C_D = 0xa4;                                            // EEPROM write address
_WAIT_REGISTER_FALSE(ptrI2C->I2C_S, I2C_IIF);                    // wait for the slae address to be sent
WRITE_ONE_TO_CLEAR_INTERRUPT(ptrI2C->I2C_S, I2C_IIF);            // clear the interrupt flag (write '1' to clear)
ptrI2C->I2C_D = ucAddressToReadFrom;                             // address to be read from
_WAIT_REGISTER_FALSE(ptrI2C->I2C_S, I2C_IIF);                    // wait for the slae address to be sent
WRITE_ONE_TO_CLEAR_INTERRUPT(ptrI2C->I2C_S, I2C_IIF);            // clear the interrupt flag (write '1' to clear)

ptrI2C->I2C_C1 = (I2C_IEN | I2C_IIEN | I2C_MSTA | I2C_MTX | I2C_RSTA); // repeated start
ptrI2C->I2C_D = 0xa5;                                            // EEPROM read address
_WAIT_REGISTER_FALSE(ptrI2C->I2C_S, I2C_IIF);                    // wait for the slave address to be sent
WRITE_ONE_TO_CLEAR_INTERRUPT(ptrI2C->I2C_S, I2C_IIF);            // clear the interrupt flag (write '1' to clear)
ptrI2C->I2C_C1 = (I2C_IEN | I2C_IIEN | I2C_MSTA);                // ensure we acknowledge multi-byte reads
(void)ptrI2C->I2C_D;                                             // dummy read

_WAIT_REGISTER_FALSE(ptrI2C->I2C_S, I2C_IIF);                    // wait for the slae address to be sent
WRITE_ONE_TO_CLEAR_INTERRUPT(ptrI2C->I2C_S, I2C_IIF);            // clear the interrupt flag (write '1' to clear)

while (iToRead-- != 0) {
    if (1 == iToRead) {                                          // last byte to read
        ptrI2C->I2C_C1 = (I2C_IEN | I2C_IIEN | I2C_MSTA | I2C_TXAK); // we don't acknowledge last byte
    }
    else if (0 == iToRead) {
        ptrI2C->I2C_C1 = (I2C_IEN | I2C_TXAK);                   // send stop condition and disable interrupts
    }

    ucReadBuffer[iReadCnt++] = ptrI2C->I2C_D;                    // put the received byte to the reception buffer
    _WAIT_REGISTER_FALSE(ptrI2C->I2C_S, I2C_IIF);                // wait for the slae address to be sent
    WRITE_ONE_TO_CLEAR_INTERRUPT(ptrI2C->I2C_S, I2C_IIF);        // clear the interrupt flag (write '1' to clear)
}
// Received data in ucReadBuffer[]

 


Note also that if you write to an EEPROM you need to poll its busy flag before reading from it since writes take a certain amount of time and reading will not return data until it has completed. 

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 件の賞賛
返信
5,039件の閲覧回数
claeskjellstrom
Contributor III

Thank you Mark,

My specific question after trying different solutions yesterday and reading datasheet word by word

is that following Freescales flowchart page 496 KL02 Reference Manual 3.1 July 2013, after switching over from transmitt to receive you should make a dummy read, giva a nack(only read 1 byte), then read the IICIF for received byte, make a stop, and read correct received byte, but when generating a stop the D register is cleared, why ?. I can go through your code but I would like to understand this behaviour.

Regards

Claes

0 件の賞賛
返信
5,032件の閲覧回数
mjbcswitzerland
Specialist V

Claes

See also Appendix A of https://www.utasker.com/docs/uTasker/uTasker_I2C.pdf which shows transaction flow based on practical tests. I never used the flow diagram in the user's guides since they are not always correct (the double-buffered version doesn't work at all if the flow chart is used as guide unless SW delays are added to work around issues with it). The uTasker I2C version has been used for >8 years in many industrial products without issues and so can be used as solid reference.

Specifically to your question:

The diagram shows the interrupt handler and not the actions required to get there.
Therefore in the decision marked as "End of address cycle (master Rx)" it means that the master has just successfully send the slave's read address and it is necessary to perform a dummy read to clear out the rx byte that was received during this transaction. This is the following in the non-interrupt code that I showed:

ptrI2C->I2C_C1 = (I2C_IEN | I2C_IIEN | I2C_MSTA | I2C_MTX | I2C_RSTA); // repeated start
ptrI2C->I2C_D = 0xa5; // EEPROM read address
_WAIT_REGISTER_FALSE(ptrI2C->I2C_S, I2C_IIF); // wait for the slave address to be sent
WRITE_ONE_TO_CLEAR_INTERRUPT(ptrI2C->I2C_S, I2C_IIF); // clear the interrupt flag (write '1' to clear)
ptrI2C->I2C_C1 = (I2C_IEN | I2C_IIEN | I2C_MSTA); // ensure we acknowledge multi-byte reads
(void)ptrI2C->I2C_D; // dummy read

The "Switch to Rx mode" just before it is presumably a firmware concept switch since there is no physical switch between modes in the I2C controller itself.

- Before the final byte is read one always switches the I2C controller to not send an ACK so that the slave recognises that the end of the transfer has been reached so "2nd to last byte to be read" not setting TXACK is correct.
In my reference it is done with

if (1 == iToRead) { // last byte to read
    ptrI2C->I2C_C1 = (I2C_IEN | I2C_IIEN | I2C_MSTA | I2C_TXAK); // we don't acknowledge last byte
}

- Generating a stop condition after receiving all data is correct and the uTasker driver reads the data after sending the stop bit so the flow diagram looks to match. Therefore this part of the diagram seems usable.

In case you are testing with a debugger attached and an I2C register view open you might have difficulties since it will be reading registers after each step and could be clearing out the Rx data before your code reads it. I don't think that the stop bit transmission itself will cause a problem with the Rx data register so it is likely that your observation technique is the cause of this issue.

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 件の賞賛
返信
5,029件の閲覧回数
claeskjellstrom
Contributor III

Hi and thank you Mark,

I see that you avoid | or & bits and for everything else that exclude handling the I2C it has allways worked. I will check again every bits and hope to solve this tonight.

By the way, yes I use a segger to debug but will allways let the debugger run to an natural end of code.

Regards

Claes 

0 件の賞賛
返信
5,026件の閲覧回数
mjbcswitzerland
Specialist V

Claes

ptrI2C->I2C_C1 = (I2C_IEN); // enable I2C controller
ptrI2C->I2C_C1 = (I2C_IEN | I2C_IIEN | I2C_MTX); // set transmit mode with interrupt enabled
ptrI2C->I2C_C1 = (I2C_IEN | I2C_IIEN | I2C_MSTA | I2C_MTX); // set master mode to cause start condition to be sent

is equivalent to
ptrI2C->I2C_C1 = (I2C_IEN); // enable I2C controller
ptrI2C->I2C_C1 |= (I2C_IIEN | I2C_MTX); // set transmit mode with interrupt enabled
ptrI2C->I2C_C1 |= (I2C_MSTA); // set master mode to cause start condition to be sent

but is about half the code size and twice as fast. It won't change behavior though.
The I2C_IIEN doesn't need to be set in this case (I forgot to remove it) but it doesn't make any difference when the I2C interrupt in the NVIC is not unmasked.

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 件の賞賛
返信
5,018件の閲覧回数
claeskjellstrom
Contributor III

Hi Mark,

I've have decided that I should attache screenshots from my oscilloscope instead and screenshots when debugging, hopefully it's clear when looking at it. The order should be first i2c_write_1, VOUT1 etc.. please let me know if you see anything because I'm blind.

Regards

Claes

i2c_write_1.pngi2c_write_2.pngi2c_read_1.pngi2c_read_2.pngVOUT01.PNGVOUT02.PNGVOUT03.PNGVOUT04.PNG

0 件の賞賛
返信
5,006件の閲覧回数
mjbcswitzerland
Specialist V

Claes

Looking at the I2C bus I see you sending 0xa4, 0x00, 0x55 (addressing the slave for a write to address 0x00 and writing the value 0x55). Then you are sending 0xa4, 0x00 to address the same address in preparation for a read. Finally you are reading by sending 0xa5 to address the device in read mode and it returns a single byte of 0x00.

Also I see that you are receiving 0x00 in the read buffer (although since this hasn't change it can't be sure - try initialising the buffer with other values first so that the data that is read is visible as changed data).

Therefore I don't see a problem with the driver part.

Where I see a problem is that the data read back doesn't match the data written but this has something to do with the EEPROM. Is its write protect enabled so that it is not writing the 0x55, for example (?)

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 件の賞賛
返信
4,998件の閲覧回数
claeskjellstrom
Contributor III

Hi Mark,

No, it's not writeprotected but the footprint is so god dammit small and it's impossible to read manufacturing code so worst scenarios would be that it is some kind of eeprom and the WP could be floating(not connected to ground). At least I know now that the code isn't that wrong and I had to re-write many things which improved the security, so I will switch to another board, and inform about eventually progress.

Many Regards to You.

/Claes

0 件の賞賛
返信
4,991件の閲覧回数
claeskjellstrom
Contributor III

Hi Mark,

Since I've got to upset about the eeprom I changed to reading LPS25H register 0x0F which is "WHO_AM_I" and it should reply 0xBD which it does on the scope but is either 0x00 or 0xFF when reading I2C0->D. When I stop the value is cleared, so dummy read gives 0xFF and stop 0x00.

Down below all inlines for switching(nothing has changed since last time.

static inline void i2c_sw_read(I2C_Type *base)
{
base->C1 &= ~I2C_C1_TX_MASK;
uint8_t test = base->D;                                             //Will change to void later
base->C1 |= I2C_C1_TXAK_MASK;
}

static inline void Clear_IICIF(I2C_Type *base)
{
base->S |= I2C_S_IICIF_MASK;
}
static inline void i2c_set_tx_mode(I2C_Type *base)
{
base->C1 |= I2C_C1_TX_MASK;
}
static inline void i2c_set_rx_mode(I2C_Type *base)
{
base->C1 &= ~I2C_C1_TX_MASK;
}
static inline void i2c_give_nack(I2C_Type *base)
{
base->C1 |= I2C_C1_TXAK_MASK;
}
static inline void i2c_give_ack(I2C_Type *base)
{
base->C1 &= ~I2C_C1_TXAK_MASK;
}
static inline void i2c_repeated_start(I2C_Type *base)
{
base->C1 |= (I2C_C1_RSTA_MASK | I2C_C1_TX_MASK);
}
static inline void i2c_start(I2C_Type *base)
{
base->C1 = (I2C_C1_IICEN_MASK | I2C_C1_MST_MASK | I2C_C1_TX_MASK);
}
static inline void i2c_stop(I2C_Type *base)
{
base->C1 &=~(I2C_C1_IICEN_MASK | I2C_C1_MST_MASK | I2C_C1_TX_MASK);
}

Any clues ??

Regards

Claes

 

 

 

I2C_Read_Data.png

0 件の賞賛
返信
4,987件の閲覧回数
claeskjellstrom
Contributor III

Hi,

I have invoked a screendump when I set a breaking point/running to line just after dummy read and now for some strange reason the "WHO_AM_I" value seems to be correct(0xBD/189 dec), even though I have not yet NACK the byte nor have I done a stop or even read the IICIF and clear it. The code after this is.


if(!(Wait_Clear_IICIF(base, 0U)))
{
return(false);
}

i2c_stop(base);

*dest = I2C0->D;

return(true);

Hope this help

Regards

Claes

 

I2C_Read_Data_dummy.png

0 件の賞賛
返信
4,983件の閲覧回数
claeskjellstrom
Contributor III

Hi,

Has anyone in this forum run the MKL part on using internal 4MHz and bus 2MHz and I2C at 100KHz ?

Regards

Claes

0 件の賞賛
返信
4,941件の閲覧回数
jingpan
NXP TechSupport
NXP TechSupport

Hi claeskjellstorm,

Yes, you can use LIRC to get this frequency.

 

Regards,

Jing

0 件の賞賛
返信
4,918件の閲覧回数
claeskjellstrom
Contributor III

Hi Jinpan,

My point was that I would like to know if any actually has used the internal 4Mhz clock(like I do) and running I2C at 100KHz ?. It seems like I'm missing last byte from slave or that the NACK is not passed to slave.

Regards

Claes

0 件の賞賛
返信
4,912件の閲覧回数
mjbcswitzerland
Specialist V

Hi

If you have a FRDM-KL02Z board you can load the attached binary file that runs the processor from 4MHz LIRC with 2MHz bus clock. The I2C to the accelerometer is configured to operate at 83kHz (maximum possible frequency in this case) and the UART is configured to 9600Baud and displays the initial read of all accelerometer registers at reset.
In the I2C menu (7) the command "acc_on" will enable print out of the accelerometer values every approx. 150ms (the values are read as fast as possible - about once each 1.5ms - and each 100th value printed). ("acc_off" to disable the print-out)

eg.
3-axis state: 0x00 0x05 0xfc 0x3e
3-axis state: 0x00 0x05 0xfc 0x3f
3-axis state: 0x00 0x05 0xfc 0x3e
3-axis state: 0x00 0x05 0xfc 0x3e
3-axis state: 0x00 0x05 0xfc 0x3f
3-axis state: 0x00 0x05 0xfc 0x3e
3-axis state: 0x0f 0x05 0xfc 0x3f
3-axis state: 0x00 0x05 0xfc 0x3e
3-axis state: 0x00 0x05 0xfc 0x3e
3-axis state: 0x00 0x05 0xfc 0x3e

This shows that the I2C operates correctly in such a configuration.

If you tell me which pins your I2C slave are on on your HW I can send you a binary that will read the values of your sensors so that you can verify that there is no HW issue involved.

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 件の賞賛
返信
4,903件の閲覧回数
claeskjellstrom
Contributor III

Hi,

I'm using my own board, however the device is MKL02Z32VFK4 and I2C0 on pins PTA3&4. This is the board which I gave up and changed it to SPI. Today I will receive another board where I'm stucked at I2C since the sensors requires that. There I'm using MKL02Z32VFG4 with I2C0 on PTB3&4 and I2C1 on PTA3&4. I will today if possible at least try to verify R/W to 24LC16.

Regards

Claes 

 

0 件の賞賛
返信
4,902件の閲覧回数
claeskjellstrom
Contributor III

By the way, I noticed that you in your reply, you mentioned 83KHz. I just clear the I2C0->F giving a division of /20 ? when busclock is 2MHz(FBI clock mode), correct ?

/Claes

0 件の賞賛
返信
4,896件の閲覧回数
mjbcswitzerland
Specialist V

Claes

I also have the ICR value of 0 set:

 

mjbcswitzerland_0-1605100887048.png

 

Practically this gives 83.4kH **bleep** speed when measured:

mjbcswitzerland_1-1605101050625.png

 

Presumably the hold times contribute to the effective speed, where it is in fact 2MHz/24 and, as the user's manual notes for vales 0x00..0x0f:

mjbcswitzerland_3-1605101324434.png

the +4 is found in this case. It can't be controlled but the behavior is essentially expected.

Regards

Mark

 

 

0 件の賞賛
返信
4,885件の閲覧回数
claeskjellstrom
Contributor III

Hi, so here we go with another board, and I'm out of any ideas whatsoever. I'm running at ~300KHz and ~100KHz. What I can see or suspect is that somewhere down the line I miss something. If I run the code all the way from setting the address I want to read from and stop emulation after the bus has switch to "READ"

Then running READ 16 bytes with a new eeprom the contents are all 0xFF which is correct. If I don't stop the emulation and let it run from start to stop the contents are all 0x00.

 

Start init

uint8_t eep_handle(I2C_Type *base)
{
if(!(I2C_Busy(base)))
{
return(i2c.status);
}
else
{
/* reading 16 bytes from block 0 starting at 0 */
eep.adr = 0U;
/* setup for reading block-0 16 bytes and check if unprog. */
i2c.i2cp = &eep.buff[0U];

/* read 16 bytes of eeprom block 0 and verify if un-programmed */
I2C_Start_U8_Xfer(base, (ADR_24LC16 | EE_BL0), eep.adr, I2C_READ);
I2C_MultiRead(base, (ADR_24LC16 | EE_BL0), EE_BLK_SIZE);

/* verify if blank/prog. a prog sets eep.blk */
if(!(verify_eep_block(&eep.buff[0U])))
{
eep.blk = 1U;
}

}
return(true);
}

 

Here is the setting of Write address

bool I2C_Start_U8_Xfer(I2C_Type *base, uint8_t dev_adr, uint8_t reg_adr, bool rw)
{
if(I2C_Busy(base))
{
i2c_start(base);
Clear_IICIF(base);
}
else
{
return(false);
}

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

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

if(rw)
{
i2c_repeated_start(base);
}
return(true);
}

And here is the last setting of READ and then 16 bytes

bool I2C_MultiRead(I2C_Type *base, uint8_t dev_adr, uint8_t nr)
{
if(!(I2C_WriteByte(base, (dev_adr | I2C_READ))))
{
return(false);
}

i2c_sw_read(base);

while(nr-- > 1U)                                               // Here I stop the emulation from start, then I start to
{
if(!(I2C_ReadByte(base, _ACK)))
{
return(false);
}
}

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

i2c_stop(base);

return(true);                                              //Here....But if I run all the way to here from start the contents                                                                     // will be 0x00
}

WHy ???????????????????????????????????

 

 

0 件の賞賛
返信
4,878件の閲覧回数
claeskjellstrom
Contributor III

Hi,

Another observation, I start to read only 2 bytes from eeprom at address 0x00 and both bytes are 0xFF, then STOP.

Then I write 1 byte data to address 0, the data is 0x35, and STOP. I'm not using the debugger and the code is compiled in release mode without any optimisation. So I simply turn the power ON/OFF to see the whole i2c stream on the scope. But.... after writing 0x35 and generate a STOP the SCL is still low.

i2c_read_write.png

Regards

Claes

0 件の賞賛
返信