I2C problem with FRAM

Tip / Sign in to post questions, reply, level up, and achieve exciting badges. Know more

cross mob
BaWe_4587896
Level 1
Level 1

Hello,

I am working on a CY8C3866AXI-040 dev kit, and trying to create an I2C communication with an external Cypress FerroRAM (and an external EEPROM too). I have already watched all the default example codes of Cypress about I2C. In the following code, I send 8 byte to the FRAM, then try to request these bytes from it. All 3 commands seems to be succeeded, because I got master status 0. But I can't see the result. The read buffer remains its original content. What is wrong in my code?
(The hardware set up and the I2C configuration in the top design: (UDB, internal clock source, 100 kbps) are OK.

Thank you for your answers.

#define I2C_DATA_CNT 8u

#define I2C_WR 0u

#define I2C_RD 1u

uint8 mr_status;

uint8 dev_sel = 0xA0;           // 1010 00 0 0

uint8 location[2] = {0x00, 0x00};

uint8 wr_buffer[I2C_DATA_CNT+2] = {0x00, 0x00, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B};

uint8 rd_buffer[I2C_DATA_CNT] = {0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87};

I2C_1_Start();

UART_1_Start();

while(1)

{

    if(UART_1_RX_STS_FIFO_NOTEMPTY) {          // Input character

        rx_buffer = UART_1_GetChar();

        if(rx_buffer == 0x77) {                // typing 'w': write

            dev_sel = 0xA0;

            mr_status = I2C_1_MasterWriteBuf(dev_sel, (uint8*) wr_buffer, sizeof(wr_buffer)+sizeof(location), I2C_1_MODE_COMPLETE_XFER);

            while(!(I2C_1_MasterStatus() & I2C_1_MSTAT_WR_CMPLT));

            CyDelay(10);

            putByteUART(mr_status);     // just puts the byte, 0 means ok

            I2C_1_MasterClearStatus();

        }

        else if(rx_buffer == 0x72) {           // 'r'  read

            // In order to do a read from a specific address, do a write operation with the memory address bytes alone:

            dev_sel = 0xA0;

            mr_status = I2C_1_MasterWriteBuf(dev_sel, (uint8*)location, sizeof(location), I2C_1_MODE_NO_STOP);

            while(!(I2C_1_MasterStatus() & I2C_1_MSTAT_WR_CMPLT));

            CyDelay(10);

            putByteUART(mr_status);

            dev_sel = 0xA1;               // Because LSB bit is the W/R

            mr_status = I2C_1_MasterReadBuf(dev_sel, (uint8*)rd_buffer, sizeof(rd_buffer), I2C_1_MODE_REPEAT_START);

            // mr_status = I2C_1_MasterReadBuf(dev_sel, (uint8*)rd_buffer, 8, I2C_1_MODE_REPEAT_START);

            while(!(I2C_1_MasterStatus() & I2C_1_MSTAT_RD_CMPLT)); //Wait till the master completes writing

            CyDelay(10);

            putByteUART(mr_status);

            putByteUART(rd_buffer[0]);  // unfortunately this byte remains 0x80

            UART_1_PutString(" ");

            putByteUART(rd_buffer[1]);  // 0x81 instead of 0x65, this is the problem

        }

    }

}

0 Likes
1 Solution

Hi BaWe_4587896​,

I believe what you are talking about is the Device Select bits of the I2C Address. I was not referring to that in my previous comment.

I am referring to the MSB of the I2C slave address. The slave address as you have mentioned is 1010 0000 which is 0xA0. But for most of PSoC I2C components we need to provide the 7-bit address excluding the R/W' bit. In your case it is 101 0000 which 0x50.

The component automatically shifts the bits and adds the R/W' bit depending on the API that you have used. For example, if you go into the definition of the read API - I2C_1_MasterReadBuf you will find that the slave address that you have provided for the API is left shifted by 1 and then the read bit is ORed with the slave address to give the final 8-bit address of the I2C slave as shown -

pastedImage_2.png

I2C_1_SLAVE_ADDR_SHIFT and I2C_1_READ_FLAG are 0x01.

So when you give 0x50 (101 0000) it gets left shifted by 1 (1010 0000) and then ORed with 0x01 to give 0xA1. This is done so that you do not have to change the slave address each time you read/write from/to the slave .

You can also remove the CyDelay(10) in line 84 as the while loop is a blocking statement and it waits for the transaction to complete. The user need not explicitly provide delays.

pastedImage_4.png

Regarding the status 0 that you were receiving, the master used to query for the slave with the wrong address. Since no slave will ACK the address there will not be any data transfer. I2C transaction as such is complete and thus a 0 is returned even though there is no address match. You can try this by disconnecting your slave and then running the master program. You will still receive a 0 as the master status.

After making these changes to the project I was able to run the I2C communication suucessfully.

Please let me know if you are still facing issue.

Thanks and Regards,

Rakshith M B

Thanks and Regards,
Rakshith M B

View solution in original post

3 Replies
Rakshith
Moderator
Moderator
Moderator
250 likes received 1000 replies posted 750 replies posted

Hi bawe_4587896​,

Can you please let me know the address of the slave? You need to provide the 7 bit address and the component takes care of the read and write bit.

pastedImage_0.png

Also can you please let me know why you have given delays in between the I2C API calls? Can you please share the entire project so that we can debug the project from our end?

Thanks and Regards,

Rakshith M B

Thanks and Regards,
Rakshith M B
0 Likes
lock attach
Attachments are accessible only for community members.

Hi Rakshith M B,

The slave device has an 8 bit-wide "device select" address (the dev_sel variable) and a 16 bit wide slave address. I think, the slave address is doesn't matter, because each byte of it is addressable (I choosed the 0x0000). The structure of the device select byte is in the attached image (and a write cycle).

When I use CyDelay, I am waiting for the answer of the slave, because I mean, it takes some time.
I try to upload the project in a rar file. Thank you the answer.

Best regards,
Bálint Wéber

Slave address.png

0 Likes

Hi BaWe_4587896​,

I believe what you are talking about is the Device Select bits of the I2C Address. I was not referring to that in my previous comment.

I am referring to the MSB of the I2C slave address. The slave address as you have mentioned is 1010 0000 which is 0xA0. But for most of PSoC I2C components we need to provide the 7-bit address excluding the R/W' bit. In your case it is 101 0000 which 0x50.

The component automatically shifts the bits and adds the R/W' bit depending on the API that you have used. For example, if you go into the definition of the read API - I2C_1_MasterReadBuf you will find that the slave address that you have provided for the API is left shifted by 1 and then the read bit is ORed with the slave address to give the final 8-bit address of the I2C slave as shown -

pastedImage_2.png

I2C_1_SLAVE_ADDR_SHIFT and I2C_1_READ_FLAG are 0x01.

So when you give 0x50 (101 0000) it gets left shifted by 1 (1010 0000) and then ORed with 0x01 to give 0xA1. This is done so that you do not have to change the slave address each time you read/write from/to the slave .

You can also remove the CyDelay(10) in line 84 as the while loop is a blocking statement and it waits for the transaction to complete. The user need not explicitly provide delays.

pastedImage_4.png

Regarding the status 0 that you were receiving, the master used to query for the slave with the wrong address. Since no slave will ACK the address there will not be any data transfer. I2C transaction as such is complete and thus a 0 is returned even though there is no address match. You can try this by disconnecting your slave and then running the master program. You will still receive a 0 as the master status.

After making these changes to the project I was able to run the I2C communication suucessfully.

Please let me know if you are still facing issue.

Thanks and Regards,

Rakshith M B

Thanks and Regards,
Rakshith M B