2

I'm trying to detect if a removable EEPROM exists in a given system, but I ran into some problems.

With configuration

 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;

The µC is a STM32F103 and it accesses a 24AA044 from Microchip; I'm using IAR Workbench with I-Jet Trace programmers.

I started out with Ack Polling like

do {
I2C_GenerateSTART( m_pI2C1, ENABLE );
while ( ! I2C_CheckEvent( m_pI2C1, I2C_EVENT_MASTER_MODE_SELECT ) );
I2C_Send7bitAddress( m_pI2C1, u8DevAddr, I2C_Direction_Transmitter );
state = I2C_CheckEvent( m_pI2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED );
} while(state==ERROR);

but here the code stops (hangs up, never returns) on first call to I2C_CheckEvent() after I2C_Send7bitAddress() until saved by the watchdog.

After I2C_Send7bitAddress(), CR1->ACK is (still) set, despite the lack of the addressed EEPROM, well, it's a controll register, so that's to be expected), but SR1->AF goes up, but SR1->TxE still is 0; at least that's what the register view of my debugger (IAR) tells me.

What I'm basically trying to do was:

 check if busy: I2C_GetFlagStatus( m_pI2C1, I2C_FLAG_BUSY );
 if not, start: I2C_GenerateSTART( m_pI2C1, ENABLE );
 control if active: while ( I2C_CheckEvent( m_pI2C1, I2C_EVENT_MASTER_MODE_SELECT)  NEQ  SUCCESS )
 set the address of the EEPORM: I2C_Send7bitAddress( m_pI2C1, u8DevAddr, I2C_Direction_Transmitter );
 control if the address has been accepted: while ( I2C_CheckEvent( m_pI2C1, 
         I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)  NEQ  SUCCESS )

but the last I2C_CheckEvent() simply hangs up if the addressed EEPROM doesn't exist.

I tried to replace it with

if ( ( ( ( *(__IO uint32_t *)m_pI2C1 + 0x14u ) ) & 0x400u ) == (uint32_t)RESET );

but didn't get the expected results.

Looking into the individual bits

    SR1Register = m_pI2C1->SR1; 
    SBBit  = SR1Register & 0x001u;
    ADDRBit = SR1Register & 0x002u;
    AFBit = SR1Register & 0x0400u;

The behavior of AF and SB seem to be as expected, but ADDR is never set, not even if there's an EEPROM connected - shouldn't it ab set when the address has been acknowledged?

But using this method (testing AF only immediately after sending the address) in real time delivers the obviously wrong results (always okay). On the other hand, TxE appears to be a reliable indicator of when the AF-Bit can be tested.

Further more, if testing for a combination of flags after sending die address like

while ( ( SBBit  NEQ  0u )  OR  ( TeXBit  EQ  0u ) ) {
        SR1Register = m_pI2C1->SR1;
        SBBit   = SR1Register & 0x001u;
        TeXBit  = SR1Register & 0x080u;   
}

the process once agains hangs upon evaluating the condition.

So my question are:

When is ADDR ever set (and for how long)?

What is the correct order to test bits (AF only when TxE if set and SB is reset)?

What on earth could make a simple test on flags which are already read from their register stuck?

Is there another way to test for missing pheripherals on I²C?

Knut S.
  • 21
  • 1
  • I²C is **NOT** discoverable and **NOT** hotpluggable bus. Strictly speaking it's not possible and in some cases even quite dangerous with an outcome of electrically broken system (with smoke and flames for real). – 0andriy May 04 '21 at 11:33

0 Answers0