Skip to main content
KSchü.2
Associate II
May 7, 2021
Question

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

  • May 7, 2021
  • 7 replies
  • 2765 views

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.

This topic has been closed for replies.

7 replies

waclawek.jan
Super User
May 7, 2021

> 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
KSchü.2Author
Associate II
May 10, 2021

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.

KSchü.2
KSchü.2Author
Associate II
May 10, 2021

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

waclawek.jan
Super User
May 10, 2021

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
KSchü.2Author
Associate II
May 11, 2021

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.

KSchü.2
KSchü.2Author
Associate II
May 11, 2021

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.

waclawek.jan
Super User
May 11, 2021

What exactly is u16StatusRegister?

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

JW

KSchü.2
KSchü.2Author
Associate II
May 11, 2021

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
KSchü.2Author
Associate II
May 11, 2021

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?

waclawek.jan
Super User
May 13, 2021

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

JW