cancel
Showing results for 
Search instead for 
Did you mean: 

I2C in Interrupt Mode stays in HAL_I2C_STATE_BUSY_TX even if the data is correct transmitted

SZank
Associate II

Hi all,

I do have a problem with the Interrupt Mode of the I2C interface. I started with the example provided by STM (I2C_TwoBoards_ComIT). I do not use two boards but one board as slave and the master is an FTDI FT4222. So sending from the FT4222 to the Nucleo Slave board does work and I print out the received string via UART. I even can send in a loop and everything is fine.

But transmission is not working. I do the following:

		// Nucleo Board (Slave) tries to send
		i2cStatus = HAL_I2C_Slave_Transmit_IT(I2cHandle, (uint8_t*)aTxBuffer, sizeof(aTxBuffer));
		if(i2cStatus != HAL_OK) {
			// Transfer error in transmission process
			Error_Handler();
		}
 
 
		while (HAL_I2C_GetState(I2cHandle) != HAL_I2C_STATE_READY) {
		}
		uartStatus = HAL_UART_Transmit(UartHandle, "Transmit ready ...\n", 12, 0xFF);

So first it all looks good, the FT4222 starts the read from the slave and even gets the correct string (atxBuffer). But then the state always stays on HAL_I2C_STATE_BUSY_TX and does not return to HAL_I2C_STATE_READY.

I do not know why because all bytes are received by the FT4222.

I hope someone can help!

Kind regards

Sebastian

5 REPLIES 5
SZank
Associate II

Of course I can provide more data if this helps. Here is the whole main() and after that the configuration function for I2C.

One additional notice:

If I do allow the STM32 to do clock stretching, the SMT32 NEVER releases the two lines and the I2C bus is not usable any more. And it is always the same.

If I do not allow the STM32 to do clock stretching, the FTDI FT4222 is able to read the data and and the read function return. But after that nvertheless the STM32 remains in the TX_STATE. :(

Kind regards

Sebastian

main():

int main(void)
{
	/* STM32F4xx HAL library initialization:
       - Configure the Flash prefetch, instruction and Data caches
       - Configure the Systick to generate an interrupt each 1 msec
       - Set NVIC Group Priority to 4
       - Global MSP (MCU Support Package) initialization
	 */
	HAL_Init();
 
	/* Configure the system clock to 180 MHz */
	SystemClock_Config();
	/* Set Interrupt Group Priority */
	HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);
	/* Use systick as time base source and configure 1ms tick (default clock after Reset is HSI) */
	HAL_InitTick(TICK_INT_PRIORITY);
	/* Initialize all configured peripherals */
	My_GPIO_Init();
	__HAL_RCC_I2C1_FORCE_RESET();
	HAL_Delay(1000);
	__HAL_RCC_I2C1_RELEASE_RESET();
	I2C_HandleTypeDef *I2cHandle = My_I2C_Init();
	//My_I2C_DMA(&I2cHandle);
	UART_HandleTypeDef *UartHandle = HAL_USART3_UART_Init();
 
	// infinite loop
	unsigned char welcome[] = "Hi, I'm the Nucleo Board\n";
	HAL_StatusTypeDef uartStatus;
	unsigned char to = 0;
 
	int i = 0;
	for (i = 0; i < 100; i++) {
		uartStatus = HAL_UART_Transmit(UartHandle, welcome, sizeof(welcome), 0xFF);
		if (uartStatus == HAL_TIMEOUT) {
			to++;
		}
	}
 
	/*BSP_LED_Init(LED2);
	BSP_LED_Init(LED3);
	// infinite loop for LED Blinking
	for (i = 0; i < 100; i++) {
		BSP_LED_Toggle(LED2);
		HAL_Delay(1000);
		BSP_LED_Toggle(LED3);
	}*/
 
 
	HAL_StatusTypeDef i2cStatus;
 
	// for testing: receiving and transmitting in endless loop
	while (1) {
		i2cStatus = HAL_I2C_Slave_Receive_IT(I2cHandle, (uint8_t *)aRxBuffer, 20);
		if (i2cStatus != HAL_OK) {
			/* Transfer error in reception process */
			Error_Handler();
		}
 
		while (HAL_I2C_GetState(I2cHandle) != HAL_I2C_STATE_READY) {
		}
		uartStatus = HAL_UART_Transmit(UartHandle, aRxBuffer, RXBUFFERSIZE, 0xFF);
 
		// Nucleo Board (Slave) tries to send
		i2cStatus = HAL_I2C_Slave_Transmit_IT(I2cHandle, (uint8_t*)aTxBuffer, sizeof(aTxBuffer));
		if(i2cStatus != HAL_OK) {
			// Transfer error in transmission process
			Error_Handler();
		}
 
 
		while (HAL_I2C_GetState(I2cHandle) != HAL_I2C_STATE_READY) {
		}
		uartStatus = HAL_UART_Transmit(UartHandle, "Transmit ready ...\n", 12, 0xFF);
	}
 
	while (1) {
		// do nothing so far
	}
}

The configuration function is the following:

/* I2C1 init function */
I2C_HandleTypeDef* My_I2C_Init()
{
	// configuration of the Pins
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.Pin = GPIO_PIN_8;
    GPIO_InitStructure.Mode = GPIO_MODE_AF_OD;
    GPIO_InitStructure.Alternate = GPIO_AF4_I2C1;
    GPIO_InitStructure.Speed = GPIO_SPEED_HIGH;
    GPIO_InitStructure.Pull = GPIO_PULLUP;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStructure);
 
    GPIO_InitStructure.Pin = GPIO_PIN_9;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStructure);
 
    /* Enable GPIO TX/RX clock */
    I2Cx_SCL_GPIO_CLK_ENABLE();
    I2Cx_SDA_GPIO_CLK_ENABLE();
    /* Enable I2C1 clock */
    I2Cx_CLK_ENABLE();
 
    hi2c.Instance = I2C1;
    hi2c.Init.ClockSpeed = 100000;
    hi2c.Init.DutyCycle = I2C_DUTYCYCLE_2;
    hi2c.Init.OwnAddress1 = 0x25 << 1;
    hi2c.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
    hi2c.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
    hi2c.Init.OwnAddress2 = 0;
    hi2c.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
    hi2c.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
 
	__I2C1_CLK_ENABLE();
	if (HAL_I2C_Init(&hi2c) != HAL_OK)
	{
		Error_Handler();
	}
    /**Configure Analogue filter
    */
  if (HAL_I2CEx_ConfigAnalogFilter(&hi2c, I2C_ANALOGFILTER_ENABLE) != HAL_OK)
  {
    Error_Handler();
  }
  HAL_NVIC_SetPriority(I2C1_EV_IRQn, 0, 1);
  HAL_NVIC_EnableIRQ(I2C1_EV_IRQn);
 
  // return the handle at the end
  return &hi2c;
}

SZank
Associate II

When I replace the interrupt based transmit function

i2cStatus = HAL_I2C_Slave_Transmit_IT(I2cHandle, (uint8_t*)aTxBuffer, sizeof(aTxBuffer));

by the blocking function

i2cStatus = HAL_I2C_Slave_Transmit(I2cHandle, (uint8_t*)aTxBuffer, sizeof(aTxBuffer), 0xFFFF);

it is working as expected. So my conclusions are:

  • The FTDI FT4222 behaves like expected, nothing goes wrong.
  • electrical connection between the two development boards are absolutly ok
  • interrupt in principal also works because the Slave_Receive() behaves like expected
  • The I2C is configured correctly (clock frequency, pullups, address ....)

The Slave_Transmit mode in interrupt mode behaves strange. But I just tried to run the example code available from ST on Github. Does really nobody have an idea what's going wrong here? I really need some more ideas because I have a bad feeling about doing so. In principle I can proceed with the current setup because the STM32 is a slave and just needs to answer when it receives a command.

But I really do want to use the interrupt or even the DMA mode.

Kind regards

Sebastian

Avan.3
Associate

I am experiencing the same problem right now. Do you found any fix?

SZank
Associate II

Hi @Avan.3​ 

my solution was to rewrite the driver on my own. I made use of the data structures given by STM but rewrote all functionality. This is because unfortunately I realized many shortcomings on the provided driver. For example it is not possible when using their driver to do random read or write and furthermore you have to send exact the number which is set when you call that function. This is not appropriate because the usual case is that the exact number of bytes for transmit or receive is not known.

As soon as I started writing my own driver everything worked. The HW is good but the SW does not have a good quality.

Even in HW there are some implementation details I don't like, e.g. the reset of SR1 when SR2 is read. There a better way would be to initiate a reset by means of one bit, ...

Kind regards

Sebastian

CPrin
Associate III

Thanks for the info. I ran into the same problem but (of course) thought that I was doing something wrong.