cancel
Showing results for 
Search instead for 
Did you mean: 

SCL line in I2C stuck at hight level when programming bare metal

AQuev.1
Associate

I am using a NUCLEO board with a STM32H7A3 MCU for lab classes in engineering. I am giving basic notions for the inner workings of most digital peripherals, so I am avoiding using HAL functions. Using basic CMSIS macros, we can use register names and bit masks to program the peripherals, helping students to understand the interaction between software and hardware.

Now it is time to work on the I2C interface. We connected a 24C16 I2C EEPROM with SCL to PB8 and SDA to PB9, and external pull-ups. Then we tested the interface and the EEPROM, writing a program using CubeXM and HAL, which works perfectly. Then I proceeded to read the I2C chapter in the manual and write code to initialize the I2C interface (at 100kHz) and to write a sequence of bytes to the EEPROM. When I tested it, though, the program froze at TXIS flag test: the flag is never set. Then I connected a logic analyzer to the SDA and SCL pins, and noticed the SDA pin working correctly, sending the "10100000" sequence (device address to the EEPROM, shifted left). However, SCL csignal is stuck at High level...

So the situation is: I have my I2C interface basically configured "almost" correctly... but when I send a byte through the interface, the EEPROM does not send the ACK back (the device does not recognize the I2C transaction because there is no SCL changes). Thus, the cycle is aborted, and TXIE is never set.

Now, the question is: why my SCL line is stuck? It is not a harware problem, since it works when I use HAL. So, it is some bug in my code. I am attaching the code for the initialization function and the multiple byte send function (the ones I have written so far). The TIMINGR value was calculated using a program made for this purpose. It can be found at:
https://github.com/nemuisan/STM32_I2C_Timing_Keisan

System clock frequency is 64MHz, same frequency at PLL1, which is the clock source selected for the I2C kernel.

Thanks in advance,

 

 

 

 

void I2C_Init(uint32_t fck, uint32_t fi2c) {
		// Clock Gating
		RCC->AHB4ENR |= RCC_AHB4ENR_GPIOBEN;
		RCC->APB1LENR |= RCC_APB1LENR_I2C1EN;
		RCC->CDCCIP2R &= ~RCC_CDCCIP2R_I2C123SEL_Msk; //I2C123SEL = 0, PLL1

		// Pins PB8 (SCL) and PB9 (SDA) in AF4
		GPIOB->MODER &= ~(GPIO_MODER_MODE8_Msk | GPIO_MODER_MODE9_Msk);
		GPIOB->MODER |= GPIO_MODER_MODE8_1 | GPIO_MODER_MODE9_1;
		GPIOB->AFR[1] &= ~(GPIO_AFRH_AFSEL8_Msk | GPIO_AFRH_AFSEL9_Msk);
		GPIOB->AFR[1] |= GPIO_AFRH_AFSEL8_2 | GPIO_AFRH_AFSEL9_2;

                // COnfiguring I2C1
		I2C1->CR1 = 0;
		I2C1->CR2 = 0;
		I2C1->TIMINGR = 0x30420F13;
		I2C1->TIMEOUTR = 0;
		I2C1->PECR = 0;
		I2C1->CR1 |= I2C_CR1_PE; // Enable
}

// In my case, I will never need transfers with more than 256 bytes
void I2C_Transmit(uint8_t devaddr, uint8_t * buf, uint8_t n) {
	uint8_t i;

	I2C1->CR2 |= devaddr | (n << 16) | I2C_CR2_AUTOEND;
	I2C1->CR2 |= I2C_CR2_START;
	for(i = 0; i < n; i++) {
		while(!(I2C1->ISR & I2C_ISR_TXIS)){}
		I2C1->TXDR = *(buf + i);
	}
	while(!(I2C1->ISR & I2C_ISR_STOPF)) {}
	I2C1->ICR = I2C_ICR_STOPCF;
	I2C1->CR2 = 0;
}

 

 

 

 

0 REPLIES 0