I2C "read" transactions that start with a write

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

cross mob
Anonymous
Not applicable

It's cool that the I2C master component supports buffer-at-a-time reads and writes with a Cypress-written builtin ISR. The only feature missing from the API is a function with a signature like:

   

uint8 MasterWriteReadBuf(uint8 slaveAddress, uint8* wrData, uint8 wrCnt, uint8* rdData, uint8 rdCnt, uint8 mode)

   

The function would write the bytes from wrData, send a restart, and then read rdCnt bytes into rdData. In other words it would be equivalent to:

   

status = MasterWriteBuf(slaveAddress, wrData, wrCnt, mode);
// possibly error handling based on status
return MasterReadBuf(slaveAddress, rdData, rdCnt, I2C_MODE_REPEAT_START);

   

except that it would be handled by the builtin ISR.

   

 

   

Almost all of my I2C interactions are this way: I need to write the "register address" within the device that I am interested in reading, and then read the contents of that register. Performing the transition without having  the interrupt handle it is tricky to do without spinning the processor waiting for the initial write transaction to take place at the much-slower-than-bus-clock I2C clock rate. This is a very, very common pattern of use of the I2C bus, almost every I2C device datasheet I know of works this way.

0 Likes
12 Replies
Anonymous
Not applicable

Yes,you've raised a valid point. Perhaps component developers browsing this forum will include this in the next revision.Till then,feel free to add that function to your copy of the component 🙂

0 Likes
Anonymous
Not applicable

I think this would be good to have this API included in later revision of creator.

0 Likes
markgsaunders
Employee
Employee
50 sign-ins 10 solutions authored 5 solutions authored

I am not a "content" guy but I've created an internal case to make sure we discuss this enhancement. I cannot predict what will be decided but we will talk about it. We appreciate all these suggestions to make Creator better!

   

As an aside, if you are on PSoC Creator 2.0, you will soon be seeing a component pack release from us, which contains updates to some existing and a couple of brand new components. This will install into your existing 2.0 image (really quickly). The idea behind these releases is that they are easier to do (because only the content changes, not the whole tool) and we can crank them out faster... which means more components and faster updates of existing ones. So, now is a good time to be making requests for component features...

   

-- Mark.

0 Likes
Anonymous
Not applicable

Anyone knows if this enhancement is planned for the future PSoC Creator?  I still don't see this in PSoC Creator 2.1.

0 Likes
Anonymous
Not applicable

Hi,

   

That’s exactly the problem where I’m also struggling with.

   

I have made a module to control a Si570 XO module. To set the frequency of that module I (among other things) have to read a register, changed it and write it back.

   

The read action should start with a write to select the register and after the write,  reading the contents of that register.

   

I tried everything:  MasterWriteBuf  with NO-STOP mode and MasterReadBuf with REPEAT_START or COMPLETE_XFER mode, but none of them are working.

   

I’m using Creater 3 with the FreeSocMini  development board with a PSoC-5.

   

I hope anybody can bring me the right solution!

   

Rob

0 Likes
Anonymous
Not applicable
        Hi Roberto48   
I2C interface is sometime difficult   
It has critical handshakes, and depend on objective device's timing   
Please refer this article, 31th Jul 2013   
And change 4 CyDelay(1) to CyDelayUs(50~500?)   
Might it be meets for you.   
0 Likes
Anonymous
Not applicable
        I FORGOT A LINK !   
http://www.cypress.com/?app=forum&id=2233&rID=82829   
0 Likes
Bob_Marlowe
Level 10
Level 10
First like given 50 questions asked 10 questions asked

I suggest not to use the high-level functions I2C_Readbuff() and I2C_WriteBuff() for the given purpose.

   

When you use I2C_SendStart(), I2C_WriteByte(),I2C_SendRestart(),I2C_ReadByte() sequences together with the appropiate waiting for a status indicating the device did finish the command you'll be probably better off.

   

Depending of using a PSoC1,,3,4,5 the syntax is slightly different.

   

 

   

Bob

0 Likes
Anonymous
Not applicable

Hi PSoC73 and Bob,

   

 

   

Thanks for your suggestions. The I2C is not realy the problem, because I have also on the same SDA and SCL lines an also modified LCD module active, and that module is working fine.

   

But I will try (as Cy called it) the manual method. I did it earlier but now I realise that I was forgotten to wait for the transfer complete status....oops..

   

As soon I succeded, I'll  tell you!

   

Rob

0 Likes
Anonymous
Not applicable
        Hi   
If you couldn't get success,   
Try to be lower Bus-clock as half of Master clock.   
I don't know root cause but   
Become working that doesn't got work I2C.   
0 Likes
Anonymous
Not applicable

Hi Bob and PSoC73,

   

Problem solved! I used following steps and it's working fine. But that was not the only problem. The main problem was in the slave address.  I put the slave address as a parameter in the I2C_Si570 module and used the same method as used in the I2C_LCD module. But in that module the slave address is shifted one bit to the right, don't know why, and that's no problem if the address is 0x40, but when the address is 0x55 (in the Si570 case) it's losing the LSB!  After I have changed that, all was working OK.

   

Maybe anyone knows the reason why in the I2C_LCD module the I2C_address is shifted for 7-bit mode. See below:

   

#define `$INSTANCE_NAME`_ADDRESS_SHIFT              (0x01u)

/* Default I2C address in 7-bit mode */
#define `$INSTANCE_NAME`_DEFAULT_I2C_ADDRESS        ((uint8)((uint8)(`$DefaultI2cAddress`u) >> \
                                                                            `$INSTANCE_NAME`_ADDRESS_SHIFT))

 

   

But anyway thanks for your help, now I can make it  a working the module!

   

Best regards,

   

Rob

   

void I2C_Si570_ReadRegs(void)
{
    uint8 ss, i;

    ss= I2C_Si570_MasterSendStart( I2C_Si570_address, 0 );  // start
    if( ss!=I2C_Si570_MSTR_NO_ERROR ) return;

    ss= I2C_Si570_MasterWriteByte( 0x07 );                             // Register 7 (start)
    if( ss!=I2C_Si570_MSTR_NO_ERROR ) return;

    ss= I2C_Si570_MasterSendStop();                                       // stop
    if( ss!=I2C_Si570_MSTR_NO_ERROR ) return;


    ss= I2C_Si570_MasterSendStart(I2C_Si570_address, 1 );     // read data
    if( ss!=I2C_Si570_MSTR_NO_ERROR ) return;
   
    for (i=0; i<=5; i++)                                                                     // Read data of 6 consec regs
    {
           I2C_Si570_tempBuf = I2C_Si570_MasterReadByte( 1 );
    }

    ss= I2C_Si570_MasterSendStop();                                          // stop
    if( ss!=I2C_Si570_MSTR_NO_ERROR ) return;
   
}

0 Likes
HeLi_263931
Level 8
Level 8
100 solutions authored 50 solutions authored 25 solutions authored

The reason for that confusion is that I2C addresses are only 7 bit long. The 8th bit is used to distinguid read and write access. But there is no real convention how to express that. Some manufacturers give you only the address part, so you need to left shift that and add the read / write bit. Others give a read and a write address, which differ only on the last bit (which is set for read access) - then you don't need to shift the address. One needs to look at the data sheet and find out how the addressing works.

0 Likes