cancel
Showing results for 
Search instead for 
Did you mean: 

I2C read() strange status register in SR2

neoirto
Associate II
Posted on November 01, 2012 at 17:32

Hi all,

I have a problem on my I2C2 configuration on STM32F4. I try in poll mode first, and I have strange result : write() seems to be ok, but not read() (see comments in code below) :

uint8_t data_received[16];
I2C_GenerateSTART(I2C2, ENABLE);
while
(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT)) {
;
}
I2C_Send7bitAddress(I2C2, COMPASS_ADDRESS_ADFAR, I2C_Direction_Receiver);
while
(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));
I2C_SendData(I2C2, ConfigRegA );
////////// This will never return from while :
// while (!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED)); /// SR2 = 00 00 00 00 00 00 01 11 SR1 = 00 00 00 00 10 00 01 00
////////// But I can pass this step by doing CUSTOM CHECK
while
(!I2C_CheckEvent(I2C2, 0x00030044)); 
/// SR2 = 00 00 00 00 00 00 00 11 SR1 = 00 00 00 00 01 00 01 00
while
(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_RECEIVED)); 
/// SR2 = 00 00 00 00 00 00 00 11 SR1 = 00 00 00 00 01 00 00 00
data_received[0] = I2C_ReceiveData(I2C2);
I2C_GenerateSTOP(I2C2, ENABLE); 

So the TRA bit from SR2 register is not set as it should be... But it should be, don't it ? Thanks in advance for your help #i2c #i2c #i2c #i2c-poll-tra-sr2
7 REPLIES 7
jpeacock2399
Associate II
Posted on November 01, 2012 at 22:27

When polling for the EV8 state (transmit data) you have to take the BTF flag into account.  The examples only show the MASTER_BYTE_TRANSMITTED  event as 0x0007 0084 but in fact it can also be 0x0007 0080, no BTF flag.

I use a state machine driven by interrupts and DMA so I don't have a fix for the ST polling example.  You may have to modify the polling routine to ignore the BTF flag on EV7 (receive) and EV8 (transmit) events.

Sorry, can't release the state machine code, company paid a small fortune for it.

  Jack Peacock
neoirto
Associate II
Posted on November 02, 2012 at 14:06

Thank you Jack,

I understand your concern about publication of valuable code. So I won't publish my result if I success, I promise ! But could you please tell me if there is an anormal

STATUS_READ_RESULT

value read (indicated in the code below)

I2C_ITConfig(I2C2, I2C_IT_ERR, ENABLE);
I2C_AcknowledgeConfig(I2C2, DISABLE); 
uint8_t data_received[16];
I2C_GenerateSTART(I2C2, ENABLE);
uint32_t STATUS_SR1_SR2_etape_m3 = I2C_GetLastEvent( I2C2 ); 
///// STATUS_READ_RESULT = 0
while
(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT)) {
;
}
uint32_t STATUS_SR1_SR2_etape_m2 = I2C_GetLastEvent( I2C2 ); 
///// STATUS_READ_RESULT = 30001
I2C_Send7bitAddress(I2C2, COMPASS_ADDRESS, I2C_Direction_Receiver);
uint32_t STATUS_SR1_SR2_etape_m1 = I2C_GetLastEvent( I2C2 ); 
///// STATUS_READ_RESULT = 30000
while
(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED)); 
///// EV6 0x00030002) /* BUSY, MSL and ADDR flags */
uint32_t STATUS_SR1_SR2_etape_0 = I2C_GetLastEvent( I2C2 ); 
///// STATUS_READ_RESULT = 30000
I2C_SendData(I2C2, ConfigRegA );
uint32_t STATUS_SR1_SR2_etape_1 = I2C_GetLastEvent( I2C2 ); 
///// STATUS_READ_RESULT = 30000
////////// This will never return from while :
while
( !I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED) 
///// EV8_2 /// BTF is set
&& !I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTING) 
///// EV8 /// BTF is NOT SET
){
#define TIMEOUT_I2C_RESET 135000
if
( --timeout == 0 ){
uint32_t STATUS_SR1_SR2_etape_2 = I2C_GetLastEvent( I2C2 ); 
///// 30044 if I2C_Ack_Enable or 30040 if I2C_Ack_Disable
timeout = TIMEOUT_I2C_RESET;
break
;
}
}
#define I2C_EVENT_MASTER_BYTE_RECEIVED_CUSTOM_ADFAR 0x00030044
while
( !I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_RECEIVED_CUSTOM_ADFAR) 
///// EV7_2_CUSTOM_ /// BTF is set
&& !I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_RECEIVED) 
///// EV7 /// BTF NOT SET
); 
data_received[0] = I2C_ReceiveData(I2C2);
I2C_GenerateSTOP(I2C2, ENABLE); 
I2C_AcknowledgeConfig(I2C2, ENABLE);

Another thing : I make all my test at 100000 Hz, but in the future, I'd like to set 400000 Hz. Actually, my PCLK1 is set atPCLK1 42000000 with HCLK_Frequency 168000000. I will need to set PCLK1 as a multiple of 10000000 according to datasheet, so I'll need to decreaseHCLK_Frequency, is that true ? Thanks in advance
jpeacock2399
Associate II
Posted on November 05, 2012 at 16:08

I've seen spurious interrupts on I2C where the event comes out as 0, so I filter those out.  No idea where it comes from.

According to the F4 manual for 400KHz I2C clock the PCLK1 must be a multiple of 10MHz, so you will have to drop the 168MHz clock down to 160MHZ, APB of 40MHz.

  Jack Peacock
neoirto
Associate II
Posted on November 06, 2012 at 12:17

Thanks again Jack.

So I clocked SYSCLK at 160 MHz (to do that, I just modified value of PLLN in the RCC->PLLCFGR register, is that true ?). It appears to be correct.

Since my last post, I obtained a working i2c config (both pollin and interrupt driven). I just noticed one error in the reference manual, but except that bogus, reading the reference manual is straigth forward to do that.

Could you please tell me more about this i2c event with status 0 : you obtain an I2Cx_EV_IRQHandler with bad status 0 ? Is that what you mean ?

Does it produce a I2Cx_ER_IRQHandler in addition ?

Is there any other strange status you catch in interrupt that you have to ignore ?

Did you notice the case you can get this strange status event ? Is it random or reproductible behaviour ?

Thanks again
jpeacock2399
Associate II
Posted on November 06, 2012 at 16:09

In the interrupt service routine I use I2C_GetLastEvent() to obtain the interrupt event.  Any events I can't parse (with the BTR flag filtered) I log as an error.  When running the driver I noticed an occasional unknown event error, which turned out to be the I2C_GetlastEvent() returning a zero.  This was on a STM3240G board, STM32F407I processor. 

No pattern as to when it occurs that I can see.  Maybe it's a spurious interrupt request due to some race condition in my code, but the driver works well enough now I'm not going to spend any more time on it.  I ignore zero events, and the driver appears to be working well with different devices on the bus. 

Maybe that's why ST doesn't provide good I2C examples.  The I2C peripheral is not one the STM32's strong points.  It does work, mostly, sort of, after a lot of coding.  Don't trust the examples in the library.

neoirto
Associate II
Posted on November 06, 2012 at 16:46

Don't trust the examples in the library.

I definitely agree with you... Hope they will fix it, because it's a damned work compared to a so simple function. Anyway it works, and I2C is cool (if SPI wasn't possible).

I wrote code to test ''un-necessary'' status apparition in IRQ, and test it. No 0 after several hours of run (STM32F405RG), but something is strange in the IRQ events : the status 0x00030000 produce an interrupt each time it happen (and it happens a lot in an I2C transfer). But why ? Is there a good reason to interrupt your code at this status apparition ? I don't think so: it's quite a lot time consumming.

Do you know if there is a trick to disable that event IRQ ?

kenny23
Associate
Posted on December 03, 2012 at 01:09

I just fixed a bug in poorly written legacy code that was detecting an SMB Alert. I fixed that by disabling SMBUS mode and using I2C but now I am seeing the ''zero'' events. I thought perhaps it was some kind of spurious thing too. Did you ever learn more?