cancel
Showing results for 
Search instead for 
Did you mean: 

After address acknowledgement, SCL line goes LOW while SDA HIGH with no data transfer in i2c stm32?

Shri
Associate II

Hi all i dont know what happen to the i2c line just after the address acknowledgement the SCL line goes LOW while SDA high and after that if i am sending data through data register I2C1_DR there is no response.Point to note that that if i initialize the I2C1 two times than again similar output(shown in output.png below) got two time but still no data transfers that means it stuck in data only while for address there is no problem .I check the the frequency of generated wave and it is 100khz which is accepted by our slave PCF8574 .Here I am using IAR EWARM for programming because i want to understand the proper register initialization & for slave PCF8574 GPIO extender..thanks please help

#include <ST/iostm32f100xB.h>
 
void I2c_sendata(char);
void i2c_init();
void delay(void);
 
int main()
{
 i2c_init(); 
 while(1)
 {
  I2c_sendata('k');
  delay();
 }
return 0;
}
 
void i2c_init()
{
  /***********************************************************************************/
  //PB6(SCL) and PB7(SDA)
  I2C1_CR1_bit.SWRST=1;//I2C Peripheral under reset state(Before resetting this bit, make sure the I2C lines are released and the bus is free.)
  RCC_APB2ENR_bit.IOPBEN=1;//Enable clock of port b
  RCC_APB1ENR_bit.I2C1EN=1;//Enable I2C1
 // RCC_APB2ENR_bit.AFIOEN=1;//Alternate function IO enable
  GPIOB_CRL_bit.MODE6=0x1;//Output mode, max speed 10 MHz
  GPIOB_CRL_bit.MODE7=0x1;//Output mode, max speed 10 MHz
  /*For bidirectional Alternate Functions, the port bit must be configured in Alternate Function Output mode (Push-Pull or Open-Drain). 
    In this case the input driver is configured in input floating mode*/
  GPIOB_CRL_bit.CNF6=0x3;//Alternate function output as open drain while input as floating
  GPIOB_CRL_bit.CNF7=0x3;//Alternate function output as open drain while input as floating
  I2C1_CR1_bit.ACK=1;//Enable Acknowledgement(Acknowledge returned after a byte is received (matched address or data) 
  I2C1_CR2_bit.ITBUFEN=1;//this will enable flag for Tx buffer empty,Rx buffer not empty
  I2C1_CR2_bit.ITEVTEN=1;//this will enable flag for SB(start bit sent when Master),stop bit received when slave(STOPF)
  I2C1_CCR_bit.F_S=0;//Standard mode 0 /Fast mode 1
/*************************************************************************************/
  //delay();
  I2C1_CR1_bit.PE=0;//disable pheripheral ,otherwise it is not allowed to make any changes in other register
  I2C1_CR2=0x0008;//APB set to 8MHZ  (other way 0b001000)
  /* In Sm mode, to generate a 100 kHz SCL frequency: If FREQR = 08, TPCLK1 = 125 ns so CCR must be programmed with 0x28(0x28 <=> 40d x 125 ns = 5000 ns.)*/
  I2C1_CCR=0x0028;
  /*In Sm mode, the maximum allowed SCL rise time is 1000 ns.If, in the I2C_CR2 register, the value of FREQ[5:0] bits is equal to 0x08 and
    TPCLK1= 125 ns therefore the TRISE[5:0] bits must be programmed with 09h */
  I2C1_TRISE=0x0009;//TRISE[5:0] must be configured only when the I2C is disabled (PE = 0).Thaths why i write it before enabling PE of I2C1_CR1
  //I2C1_DR=(0x20<<1)|(0x00000000);//send address and than write(Master Transmitter)
  I2C1_CR1_bit.PE=1;//enable pheripheral
  I2C1_CR1_bit.START=1;//Start/Repeated Start
  while(!(I2C1_SR1_bit.SB));//wait for 
  I2C1_DR=0x4E;   
//while(!(I2C1_SR1_bit.AF)); //End of address transmission(the bit is set after the ACK of the byte)
 
}
 
void I2c_sendata(char data)
{
 I2C1_DR=data;
 while(!(I2C1_SR1_bit.TxE));
  
 //I2C1_CR1_bit.STOP=1;//End Termination  
}
 
void delay(void){
int i = 1000000; /* About 1/4 second delay */
while (i-- > 0)
asm("nop");
}

0693W000006Go4xQAC.png 

6 REPLIES 6
TDK
Guru

Something is holding down the clock, possible the slave or master.

https://www.i2c-bus.org/i2c-primer/clock-generation-stretching-arbitration/

The little hiccup at your cursor isn't a valid I2C signal. Could be related to that. Can't have SCL go low while SDA is high. You could avoid initializing the pins as AF until the peripheral is active to avoid this.

If you feel a post has answered your question, please click "Accept as Solution".

Exceedingly few people are going to be interested in unpacking and debugging others register level code.

Test if it works with standard libraries (SPL, HAL, etc) and if it does, then unwind the code from there and check the sequences/nuances against your own implementation.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..

Sir actually i followed the same approach as you told that first created the project in STM32 cube IDE and than from there tried to follow the sequences....But the problem with this approach is (correct me if i am wrong) there is no concept of register is there instead everything is address Like if i trace I2C1 than it lead me to:

"#define I2C1_BASE            (APB1PERIPH_BASE + 0x00005400UL)" which is very difficult to trace one by one.I know register on the background pointing to some address but it is very difficult to trace through address instead register.............please correct me if i am wrong..thanks and waiting for you answer

Shri
Associate II

But why Master/Slave holding down the clock sir...i have two different SLAVES i have tested with both but both of them showing similar behavior..any suggestion sir

Typically one looks at the peripherals with the help of the IDE debugger. The SFRs tab in STM32CubeIDE, for instance.

If you feel a post has answered your question, please click "Accept as Solution".

Like I said in the post, it could be because the I2C signal you're providing is invalid. I'd fix that before anything else.

If you feel a post has answered your question, please click "Accept as Solution".