PSoC5LP : Clock of fixed function I2C componnent

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

cross mob
MiNe_85951
Level 7
Level 7
Distributor - TED (Japan)
50 likes received 500 replies posted 50 solutions authored

Hi,

We use fixed function I2C slave component of PSoC5LP.

1) Place I2C Slave ( fixed function ) component in PSoC Creator.

2) Set the data rate to 100 ksps.

3) Set the BUS_CLK ( CPU ) and MASTER_CLK to 24MHz.

It works normally after the build.

However, while the CPU is running,
Switch 24MHz of CPU_CLK to 3MHz by using API.

Then, the following events were confirmed.

-- I2C data rate becomes 12.5kbps ( = 100kbps / 8 )

-- In I2C communication, Communication fails if 4 bytes or more data is read at a time. ( Communication successful up to 3 Bytes )

Is the above recognition correct?
Do you have a way to improve these?

Regards,

0 Likes
1 Solution
Len_CONSULTRON
Level 9
Level 9
Beta tester 500 solutions authored 1000 replies posted

MaMi,

It appears your I2C clock is derived from the BUS_CLK (or MASTER_CLK).  When you reduce the BUS_CLK by a factor of 8, you end up reducing the SPI clock by the same factor.

There are two ways to prevent this.  One way requires a little SW and the other is only at compile-time.

If you are willing to share your project, I can directly help.

If not, the SW method is to change the I2C clock divider value using I2C_SetDivider(uint16 clkDivider).

Perform the following steps:

uin32_t clockval;

// Read the I2C clock divider value.

clockval = I2C_GetDividerRegister();  // the value is the actual divider value -1

clockval += 1;    // adjust to correct for the value -1

clockval *= 8;    // scale the clock back up to 100 Kbps when using BUS_CLK = 3MHz

clockval -= 1;    // re-adjust it back to value-1

// Set this adjusted value in the I2C clock

I2C_SetDivider(clockval);    // You should be back to 100 Kbps

The other way involves sourcing the I2C clock from the MASTER_CLK (@ 24MHz) and leaving it at 24MHz.  This way, the I2C clock remains at 100 Kbps.

Use the API call CyBusClk_SetDivider() to change the BUS_CLK divider to scale the BUS_CLK from 24MHz to 3 MHz by setting divider value to 8-1.

pastedImage_4.png

Len

Len
"Engineering is an Art. The Art of Compromise."

View solution in original post

8 Replies
Len_CONSULTRON
Level 9
Level 9
Beta tester 500 solutions authored 1000 replies posted

MaMi,

It appears your I2C clock is derived from the BUS_CLK (or MASTER_CLK).  When you reduce the BUS_CLK by a factor of 8, you end up reducing the SPI clock by the same factor.

There are two ways to prevent this.  One way requires a little SW and the other is only at compile-time.

If you are willing to share your project, I can directly help.

If not, the SW method is to change the I2C clock divider value using I2C_SetDivider(uint16 clkDivider).

Perform the following steps:

uin32_t clockval;

// Read the I2C clock divider value.

clockval = I2C_GetDividerRegister();  // the value is the actual divider value -1

clockval += 1;    // adjust to correct for the value -1

clockval *= 8;    // scale the clock back up to 100 Kbps when using BUS_CLK = 3MHz

clockval -= 1;    // re-adjust it back to value-1

// Set this adjusted value in the I2C clock

I2C_SetDivider(clockval);    // You should be back to 100 Kbps

The other way involves sourcing the I2C clock from the MASTER_CLK (@ 24MHz) and leaving it at 24MHz.  This way, the I2C clock remains at 100 Kbps.

Use the API call CyBusClk_SetDivider() to change the BUS_CLK divider to scale the BUS_CLK from 24MHz to 3 MHz by setting divider value to 8-1.

pastedImage_4.png

Len

Len
"Engineering is an Art. The Art of Compromise."
MiNe_85951
Level 7
Level 7
Distributor - TED (Japan)
50 likes received 500 replies posted 50 solutions authored

Len-san,

We would like to conrifm two points.

1.

In I2C communication, Communication fails if 4 bytes or more data is read at a time. ( Communication successful up to 3 Bytes )

Do you have comments on the above issue.

Do you think this behavior is due to a clock drop?

2.

You say that :

The other way involves sourcing the I2C clock from the MASTER_CLK (@ 24MHz) and leaving it at 24MHz.  This way, the I2C clock remains at 100 Kbps.

We think that the clock source of fixed function I2C is fixed to the bus clock. See the image below.

pastedImage_1.png

Regards,

0 Likes

MaMi.

1.

In I2C communication, Communication fails if 4 bytes or more data is read at a time. ( Communication successful up to 3 Bytes )

Do you have comments on the above issue.

Do you think this behavior is due to a clock drop?

What I2C Rx status are you using to determine when to read the 4 bytes?  I've looked at the I2C component.  There does not appear to have a 4 byte FIFO (or any FIFO) as part of the Rx data.  Instead you have to initialize the data buffer location to store the incoming data using I2C_SlaveInitWriteBuf().

Are you using I2C_SlaveGetWriteBufSize() to make sure that 4 bytes are in the buffer before trying to read it?   If the I2C clock is reduced by 8 times, then it will take 8 times longer to transfer the 4 bytes than if the I2C was at full speed (100Kbps).

Depending on what you are using to determine the time to read 4 bytes, it may not be correct.  Using the I2C_SlaveGetWriteBufSize() will determine if 4 bytes are in the buffer for you to read.  Additionally you need to perform a  I2C_SlaveClearWriteBuf() after reading the required bytes to clear the buffer count.

2.

You say that :

The other way involves sourcing the I2C clock from the MASTER_CLK (@ 24MHz) and leaving it at 24MHz.  This way, the I2C clock remains at 100 Kbps.

You are correct.  This is probably because you are using the Fixed Function version of I2C or the UDB version with the internal clock.  If you change the I2C configuration to UDB with external clock, you can control the input clock source.

pastedImage_6.png

pastedImage_8.png

Configure the external I2C clock like this:

pastedImage_10.png

This way the I2C component will be sourced from the MASTER_CLK (always at 24MHz) and will have the required clock frequency of 1.6MHz to clock the datarate at 100Kbps.

Len

Len
"Engineering is an Art. The Art of Compromise."
0 Likes
MiNe_85951
Level 7
Level 7
Distributor - TED (Japan)
50 likes received 500 replies posted 50 solutions authored

Len-san,


Thank you for your reply.

I would like you to additionally tell us about 1.

Before changing the clock, continuous reading of 4 bytes is possible.
If you change the clock from 24MHz to 3MHz,
An error occurs when reading 4 bytes continuously (normal up to 3 bytes, 4 bytes error).

This behavior was the same not only for fixed function I2C but also for UDB based I2C.

Did you see a reproduction of the behavior of this issue?

Regards,

0 Likes

You're welcome MaMi.

As part of my reply regarding 1. I asked:

What I2C Rx status are you using to determine when to read the 4 bytes?  I've looked at the I2C component.  There does not appear to have a 4 byte FIFO (or any FIFO) as part of the Rx data.  Instead you have to initialize the data buffer location to store the incoming data using I2C_SlaveInitWriteBuf().

Are you using I2C_SlaveGetWriteBufSize() to make sure that 4 bytes are in the buffer before trying to read it?   If the I2C clock is reduced by 8 times, then it will take 8 times longer to transfer the 4 bytes than if the I2C was at full speed (100Kbps).

I never received a reply from you.   In general, you need some feedback from the I2C component whether there are 4 bytes in the Rx buffer.  This is true whether you are transferring at 100Kbps (CPU @ 24MHz) or at 12.5 Kbps (CPU @ 3MHz).

Len

PS:  If you are willing to share your project, I can be more specific to your issue.

Len
"Engineering is an Art. The Art of Compromise."
0 Likes
MiNe_85951
Level 7
Level 7
Distributor - TED (Japan)
50 likes received 500 replies posted 50 solutions authored

Len-san,

The usage was corrected. Excuse me.

This fixed function I2C used was a "master setting", "not a slave".

The following API is used to read data.

I2C_MasterReadBuf (uint8 slaveAddress, uint8 * rdData, uint8 cnt, uint8 mode)

Before the above call, I2C_DisableInt () and I2C_MasterClearStatus () are executed.

The usage of the I2C_MasterReadBuf () function is the method described in the Code Example.

When you change the 24MHz of master clock to 3MHz,

Could you confirm whether this API does not work properly?

The following are not directly called and used.

I2C_SlaveInitWriteBuf ()

I2C_SlaveClearWriteBuf ()

Regards,

0 Likes

MaMi,

I'm confused.  Your first post said:

We use fixed function I2C slave component of PSoC5LP.

1) Place I2C Slave ( fixed function ) component in PSoC Creator.

2) Set the data rate to 100 ksps.

3) Set the BUS_CLK ( CPU ) and MASTER_CLK to 24MHz.

Yet your last post said:

This fixed function I2C used was a "master setting", "not a slave".

The following API is used to read data.

Which is it?

If it happens to be that the PSoC5 I2C fixed function block is acting as a Master, what is the Slave?  Is it another PSoC?

If the slave is not a PSoC and not under your control, my understanding is that normally the I2C peripherals are clocked at 100KHz and if acceptable to both ends they can be clocked faster.

If you have NO CONTROL of the Slave and you change from MASTER_CLK = 24MHz (I2C clock = 100KHz) to MASTER_CLK = 3MHz (I2C = 12.5KHz), the Slave may not like it due to its SW implementation.  It might be timed improperly and is expecting the last byte of I2C data from the Master to be completed sooner than it actually is.

If you have to switch the PSoC CPU clock from 24MHz to 3MHz, please take one of my previous suggestions.  For example, clock the I2C FF block from the MASTER_CLK (always at 24MHz) and change the BUS_CLK divider from  divide by 1 to divide by 8.

Len

Len
"Engineering is an Art. The Art of Compromise."
0 Likes

MaMi,

I hope all is well with you.   I haven't seen a response from you in a week.

Let me try to answer another question of yours.

When you change the 24MHz of master clock to 3MHz,

Could you confirm whether this API does not work properly?

I don't have any I2C peripherals.  I tend to use SPI peripherals.  However in either case, I2C or SPI are synchronous serial protocols. This means that the data and clock are separate signals.   Each data bit is clocked.  When I converted a SPI component to I2C component in a previous project, I also set the I2C master clock to 24MHz.  The oscilloscope I am using can decode the I2C (or SPI) data and clock and the output is as expected.

When I set the I2C master clock to 3 MHz, the output was 8 times slower but still correct.  Therefore, I would say the API is working as specified.

You can do something similar if you have a oscilloscope.  You don't need to have it decode the I2C.  You can decoded it by "eye".  The output should be identical except the 3MHz will be 8 times slower.

Theory #1

I suspect that the I2C slave peripheral you are using is effectively dropping the last byte of 4 bytes because it is taking too long to transmit.  It is probably timing out because it is expecting the data to be transmitted at 100Kbps instead of 12.5Kbps at 3MHz clock.

What is the I2C slave peripheral you are using?  What is the part #?

Theory #2

It could be possible that something in your PSoC SW is aborting the last byte of transmission as the I2C master.  I can't know if this is the case without you sharing your project.

I'm trying to help as much as I can, but I'm lacking your project specifics to be more accurate.

Len

Len
"Engineering is an Art. The Art of Compromise."
0 Likes