FTDI Community

General Category => Discussion - Software => Topic started by: scorpioprise on March 19, 2019, 03:51:46 PM

Title: I2C misunderstanding
Post by: scorpioprise on March 19, 2019, 03:51:46 PM
Hi Everybody, I'm working on my custom board, so it's not a good starting point....
I have a 64K I2C serial eeprom. But I don't really understand what's wrong...

Of course, I tested the example on the demo board (MM900EV1A) and worked. (2K eeprom)

First problem, No read - no write.
The location address is 12bit long, so I got the source and altered, but no success.

Code: [Select]
int8_t i2cm_write_twoByte(const uint8_t addr, const uint16_t loc,
const uint8_t *data, uint16_t number_to_write) {
int8_t ret = 0;

if (isHighSpeed) {
/* In high speed mode, the following sequence has to be done before each data transfer
Write Master code 0x09 to I2CMSA and the HIGH SPEED command to I2CMCR */
I2CM->I2CM_SLV_ADDR = 0x09;
I2CM->I2CM_CNTL_STATUS = I2C_FLAGS_HS | I2C_FLAGS_RUN;

/* Wait until I2CM is no longer busy */
if (i2c_wait_for()) { /* An Error Occurred */
ret = -1;
}
}

if (ret == 0) {
/* Write slave address to SA */
I2CM->I2CM_SLV_ADDR = addr;
/* Write command byte address MSB to BUF */
I2CM->I2CM_DATA = (uint8_t) ((loc & 0xFF00) >> 8);

/* Check that the bus is not occupied by another master
(this step is not needed in single-master system or in high speed mode since
arbitration takes place during transmission of the master code) */
if (isHighSpeed == 0) {
while (I2CM->I2CM_CNTL_STATUS & MASK_I2CM_STATUS_BUS_BUSY) {
}
}

/* Write command to I2CMCR to send Start and command byte. */
I2CM->I2CM_CNTL_STATUS = I2C_FLAGS_START | I2C_FLAGS_RUN;
if (i2c_wait_for()) { /* An Error Occurred */
ret = -1;
}
}
if (ret == 0) {
/* Write command byte address LSB to BUF */

I2CM->I2CM_DATA = (uint8_t) (loc & 0xFF);
I2CM->I2CM_CNTL_STATUS = I2C_FLAGS_RUN;
if (i2c_wait_for()) { /* An Error Occurred */
ret = -1;
}
}

if (ret == 0) {
if (number_to_write) {
while (number_to_write-- && ret == 0) {
/* Write command to I2CMCR to send data byte. */
I2CM->I2CM_DATA = *data++;
I2CM->I2CM_CNTL_STATUS = I2C_FLAGS_RUN;
if (i2c_wait_for()) { /* An Error Occurred */
ret = -1;
}
}
}
}

/* Write command to I2CMCR to send Stop. */
I2CM->I2CM_CNTL_STATUS = I2C_FLAGS_STOP;
if (ret == 0) {
i2c_wait_for();
}

return ret;
}

Code: [Select]
int8_t i2cm_read_twoByte(const uint8_t addr, const uint16_t loc, uint8_t *data,
uint16_t number_to_read) {
int8_t ret = 0;

if (isHighSpeed) {
/* In high speed mode, the following sequence has to be done before each data transfer
Write Master code 0x09 to I2CMSA and the HIGH SPEED command to I2CMCR */
I2CM->I2CM_SLV_ADDR = 0x09;
I2CM->I2CM_CNTL_STATUS = I2C_FLAGS_HS | I2C_FLAGS_RUN;

/* Wait until I2CM is no longer busy */
if (i2c_wait_for()) {
ret = -1;
}
}

if (ret == 0) {
/* Write slave address to SA */
I2CM->I2CM_SLV_ADDR = addr;
/* Write command byte address to BUF */
I2CM->I2CM_DATA = (uint8_t) ((loc & 0x1f00) >> 8);

/* Check that the bus is not occupied by another master
(this step is not needed in single-master system or in high speed mode since
arbitration takes place during transmission of the master code) */
if (isHighSpeed == 0) {
while (I2CM->I2CM_CNTL_STATUS & MASK_I2CM_STATUS_BUS_BUSY) {
}
}

/* Write command to I2CMCR to send Start and command byte. */
I2CM->I2CM_CNTL_STATUS =
I2C_FLAGS_START | I2C_FLAGS_RUN | I2C_FLAGS_ACK;

if (i2c_wait_for()) {
ret = -1;
}
}
if (ret == 0) {
I2CM->I2CM_DATA = (uint8_t) (loc & 0x00ff);
I2CM->I2CM_CNTL_STATUS = I2C_FLAGS_RUN | I2C_FLAGS_ACK;
if (i2c_wait_for()) {
ret = -1;
}
}
if (ret == 0) {
/* Write slave address to SA with R operation */
I2CM->I2CM_SLV_ADDR = addr | 0x01;

if (number_to_read <= 1)
/* Receive with a NACK */
I2CM->I2CM_CNTL_STATUS = I2C_FLAGS_START | I2C_FLAGS_RUN;
else
/* Receive with an ACK */
I2CM->I2CM_CNTL_STATUS = I2C_FLAGS_START | I2C_FLAGS_RUN
| I2C_FLAGS_ACK;

if (i2c_wait_for()) {
ret = -1;
}
}

if (ret == 0) {
while (number_to_read) {
*data++ = I2CM->I2CM_DATA;
number_to_read--;

if (number_to_read) {
if (number_to_read == 1)
/* Last one, Receive with a NACK */
I2CM->I2CM_CNTL_STATUS = I2C_FLAGS_RUN;
else
/* Receive with an ACK */
I2CM->I2CM_CNTL_STATUS = I2C_FLAGS_RUN | I2C_FLAGS_ACK;

/* Write command to I2CMCR to read data byte.
I2CM->I2CM_CNTL_STATUS = I2C_FLAGS_RUN; */
if (i2c_wait_for()) {
ret = -1;
break;
}
}
}
}

/* Write command to I2CMCR to send Stop. */
I2CM->I2CM_CNTL_STATUS = I2C_FLAGS_STOP;
if (ret == 0) {
i2c_wait_for();
}

return ret;
}

Memory is Microchip 24LC64, 5 pin SOT23 (no hardware address).

Any idea where to look for the problem?
Title: Re: I2C misunderstanding
Post by: FTDI Community on March 22, 2019, 04:28:07 PM
Please note that our new Bridgetek Community is now open.
Please note that we have created the Bridgetek Community to discuss all Bridgetek products e.g. EVE, MCU.
Please follow this link and create a new user account to get started.

Bridgetek Community (http://www.brtcommunity.com/)

The FT90x library driver for I2C only supports 8-bit addressing.
However, you could take a look at FT90x UVC Webcam  (https://www.ftdichip.com/Support/SoftwareExamples/FT90X.htm#FT90x UVC Webcam) Example. The OV5640 module code includes a set of subroutines to allow 16-bit addressing on the I2C bus. These may be reused for other projects.
The source code is downloadable at the link above.

This should help you access the 24LC64 64k range.

The device addressing of both EEPROMs are very similar. The control byte format starts with 1010.

Maybe someone else on the Bridgetek Community can help further with this.

Best Regards,
FTDI Community