cancel
Showing results for 
Search instead for 
Did you mean: 

On initiating I²C communication, status register SR1 gets reset immediately

KSchü.2
Associate II

With the following code to handshake an EEPROM

STM_enableRCCAPB1PeriphClock( RCC_APB1Periph_I2C1, ENABLE );

STM_resetRCCAPB1PeriphCmd( RCC_APB1Periph_I2C1, DISABLE );

I2C_Cmd( m_pEE_I2C_TYPE, ENABLE );

I2C_ITConfig( m_pEE_I2C_TYPE, I2C_IT_ERR, ENABLE );

I2C_InitStructure.I2C_Mode = EE_I2C_MODE;

I2C_InitStructure.I2C_DutyCycle = EE_I2C_DUTY_CYCLE;

I2C_InitStructure.I2C_OwnAddress1 = EE_I2C_OWN_ADDRESS;

I2C_InitStructure.I2C_Ack = EE_I2C_ACK;

I2C_InitStructure.I2C_AcknowledgedAddress = EE_I2C_ACK_ADDR;

I2C_InitStructure.I2C_ClockSpeed = EE_I2C_CLOCK_SPEED;

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 BITOR GPIO_Pin_7;

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;

/* Generate the START condition */

I2C1->CR1 |= I2C_CR1_START;

/* wait until START condition is set */

while ( NOT ( I2C1->SR1 BITAND I2C_SR1_SB ) )

{

}

/* send the address of the EEPROM with r/w-bit reset */

address = EE_EXT_ADDRESS;

address |= 1u; // read / receiver

I2C1->DR = address;

/* wait for either ADDR (ACK) oder AF (NACK) to be set */

u16StatusRegister = 0x00u;

while ( NOT ( ( u16StatusRegister BITAND I2C_SR1_ADDR ) BITOR (

u16StatusRegister BITAND I2C_SR1_AF ) ) )

{

u16StatusRegister = I2C1->SR1;

}

I see the rising of either AF or ADDR in the debugger's register view after executing

I2C1->DR = address, but as soon as I execute u16StatusRegister = 0x00u, all bits in SR1 are reset.

Could anybody guess why that's happening?

I'm using IAR workbench 7.50 and IAR I-jets debugger on a STM32f103, and there are no interrupt routines coded.

10 REPLIES 10

> as soon as I execute u16StatusRegister = 0x00u, all bits in SR1 are reset

How do you know? And what about other I2C registers? Read them out and post.

JW

KSchü.2
Associate II

I'm watching them in the register view of my IDE (IAR Workbench, via IAR I-jet Trace programmers).

Set Bits before and after are:

Case 1 (Success):

CR1->ACK: 1 | 1

CR1->PE: 1 | 1

CR2->ITERREN: 1 | 1

CR2->FREQ: 0x12 | 0x12

OAR1->ADD7: 0x50 | 0x50

DR: 0xA4 | 0xA4

SR1->AF: 0 | 0

SR1->TxE: 1 | 1

SR1->ADDR: 1 | 0

SR2->TRA: 1 | 1

SR2->BUSY: 1 | 1

SR2->MSL: 1 | 1

CCR->F_S: 1 | 1

CCR->CCR: 0x14 | 0x14

TRISE->TRISE: 0x06 | 0x06

Case 2 (Failure):

CR1->ACK: 1 | 1

CR1->PE: 1 | 1

CR2->ITERREN: 1 | 1

CR2->FREQ: 0x12 | 0x12

OAR1->ADD7: 0x50 | 0x50

DR: 0xA4 | 0xA4

SR1->AF: 1 | 0

SR1->TxE: 0 | 0

SR1->ADDR: 0 | 0

SR2->TRA: 0 | 0

SR2->BUSY: 1 | 1

SR2->MSL: 1 | 1

CCR->F_S: 1 | 1

CCR->CCR: 0x14 | 0x14

TRISE->TRISE: 0x06 | 0x06

So the two bits I'm interested in are being somehow automatically reset before I can access them.

It's also not an debugger (alt least not a stepping/tracing) issue, because I can reproduce this in the life device by reading SR1 and setting an LED depending on the status of those bits.

Above register settings were from using write access.

With read access the results are:

Case 1 (Success):

CR1->ACK: 1 | 1

CR1->PE: 1 | 1

CR2->ITERREN: 1 | 1

CR2->FREQ: 0x12 | 0x12

OAR1->ADD7: 0x50 | 0x50

DR: 0xA4 | 0xA5

SR1->AF: 0 | 0

SR1->RxNE: 0 | 1

SR1->BTF: 0| 1

SR1->ADDR: 1 | 0

SR2->TRA: 0 | 0

SR2->BUSY: 1 | 1

SR2->MSL: 1 | 1

CCR->F_S: 1 | 1

CCR->CCR: 0x14 | 0x14

TRISE->TRISE: 0x06 | 0x06

Case 2 (Failure):

CR1->ACK: 1 | 1

CR1->PE: 1 | 1

CR2->ITERREN: 1 | 1

CR2->FREQ: 0x12 | 0x12

OAR1->ADD7: 0x50 | 0x50

DR: 0xA4 | 0xA4

SR1->AF: 1 | 0

SR1->RxNE: 0 | 0

SR1->BTF: 0| 0

SR1->ADDR: 0 | 0

SR2->TRA: 0 | 0

SR2->BUSY: 1 | 1

SR2->MSL: 1 | 1

CCR->F_S: 1 | 1

CCR->CCR: 0x14 | 0x14

TRISE->TRISE: 0x06 | 0x06

The I2C in the STM32 are tricky (and there are several versions of them, in different families, which doesn't make things much easier).

ADDR gets cleared automatically by reading SR1 and SR2, so observing I2C registers in debugger is a bad idea; and you appear to read it too. AF shouldn't get cleared automatically so that's a mystery, unless you have som interrupt installed which handles the I2C registers/events.

JW

KSchü.2
Associate II

Thanks; I tried the same without a debugger, signaling the state of the process with LEDs, and the result is the same.

I have to do at least one read access, but only from SR1, I don't actively access SR2.

Both IRQ vectors (EVT and ERR) point to empty handlers.

I'm totally out of my depth in unterstanding what's happening here.

What exactly is u16StatusRegister?

Try to reduce the code to absolute minimum but complete compilable example still exhibiting the problem, and post.

JW

And to top that off: Now I've changed the project (but not the hardware and not the configuration) I see that ADDR is still set after the evaluation, if I pass there by running in the debugger without breakpoints from the start; but when I step into those lines, I still get the old results of premature resets (with the same procedure I used before).

Its just maddening.

Just a local temporary buffer of uint16_t to reduce reading access to SR1 to once per check.

I tried that, but e.g. ( NOT ( ( ( I2C1->SR1 ) BITAND I2C_SR1_ADDR ) OR ( ( ( I2C1->SR1 ) BITAND I2C_SR1_AF ) ) ) ) didn't change anything.

KSchü.2
Associate II

I re-coded it a bit:

 /* Generate the START condition */

 I2C1->CR1 |= I2C_CR1_START;

 /* wait until START condition is set */

 while ( NOT ( I2C1->SR1 & I2C_SR1_SB ) ) { }

 /* send the address of the EEPROM with r/w-bit reset */

 address = EE_EXT_ADDRESS | 1u; // read / receiver     

 I2C1->DR = address;          

 /* wait for either ADDR (ACK) oder AF (NACK) to be set */

 u8Timeout = MaxWaitForACK;

 while ( ! ( ( I2C1->SR1 & ( I2C_SR1_AF | I2C_SR1_ADDR | I2C_SR1_BTF | I2C_SR1_TXE | I2C_SR1_RXNE ) ) || ( u8Timeout == 0u ) ) ) {

  u8Timeout--;

 }

 if ( I2C1->SR1 & ( I2C_SR1_ADDR | I2C_SR1_BTF | I2C_SR1_TXE | I2C_SR1_RXNE ) ) {

   /* BTF set <-- EEPROM send ACK */ /* ADDR set <-- EEPROM send ACK */

   bRetVal = TRUE;

 }

 else {

   /* BTF not set <-- Timeout <-- EEPROM send NACK */ /* AF set <-- NACK read */

   bRetVal = FALSE;

 }

This works always (single step, debugging context, and live) in the fail case, but in the success case, it only works when stepping or debugging, not live.

And even more curious: when breaking after the evaluation, see AF set in the fail case, which I don't do when stepping through.

Any thoughts?