cancel
Showing results for 
Search instead for 
Did you mean: 

SPI stops working when enable I2C?

MCris.4
Associate II

Hello, I'm trying to use I2C and SPI simultaneously on an STM32F103C6TX.

Both are working properly when only one of them is activated. However, when activating I2C peripheral with SPI already activated, SPI clock still works but the MOSI pin stops working.

Below, the configuration is presented. SPI is remapped to pins PB3, 4 and 5.

void HAL_SPI_MspInit(SPI_HandleTypeDef* hspi)
	{
	  GPIO_InitTypeDef GPIO_InitStruct = {0};
	  if(hspi->Instance==SPI1)
	  {
		  /* Peripheral clock disable */
		  __HAL_RCC_SPI1_CLK_DISABLE();
		  __HAL_RCC_SPI1_CLK_ENABLE();
		  __HAL_RCC_GPIOA_CLK_ENABLE();
		  __HAL_RCC_GPIOB_CLK_ENABLE();
		  /**SPI1 GPIO Configuration
		  PA15    ------> SPI1_CS
		  PB3     ------> SPI1_SCK
		  PB4     ------> SPI1_MISO
		  PB5     ------> SPI1_MOSI
		  */
 
		  GPIO_InitStruct.Pin = GPIO_PIN_3|GPIO_PIN_5;
		  GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
		  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
		  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
//		  HAL_GPIO_WritePin(GPIOB, GPIO_PIN_3, GPIO_PIN_RESET);
//		  HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5, GPIO_PIN_RESET);
 
		  GPIO_InitStruct.Pin = GPIO_PIN_4;
		  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
		  GPIO_InitStruct.Pull = GPIO_NOPULL;
		  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
//		  HAL_GPIO_WritePin(GPIOB, GPIO_PIN_4, GPIO_PIN_RESET);
 
		  __HAL_AFIO_REMAP_SPI1_ENABLE();
 
		  GPIO_InitStruct.Pin = GPIO_PIN_15;
		  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
		  GPIO_InitStruct.Pull = GPIO_NOPULL;
		  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
		  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
		  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_15, GPIO_PIN_SET);
 
		  __HAL_RCC_SPI1_CLK_ENABLE();
    }
  }

Next, the I2C configuration is displayed. I2C is remapped to pins PB8 (SCL) and PB9 (SDA). To be more precise, after executing the macro

__HAL_AFIO_REMAP_I2C1_ENABLE();

SPI MOSI pin stop working.

void HAL_I2C_MspInit(I2C_HandleTypeDef* hi2c)
  {
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    if(hi2c->Instance==I2C1)
    {
      /**I2C1 GPIO Configuration
      PB8     ------> I2C1_SCL
      PB9     ------> I2C1_SDA
      */
      /* GPIO Ports Clock Enable */
      __HAL_RCC_GPIOB_CLK_ENABLE();
 
 
      /*Configure GPIO pin Output Level */
      HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8|GPIO_PIN_9, GPIO_PIN_RESET);
 
      GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_9;
      GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
      GPIO_InitStruct.Pull = GPIO_NOPULL;
      GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
      HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
 
      /* Peripheral clock enable */
	  __HAL_RCC_I2C1_CLK_ENABLE();
 
      __HAL_AFIO_REMAP_I2C1_ENABLE();
	}
  }

I also tried to change order of CLKs activation and even the order in which I2C and SPI are enabled. But it still not working.

Thank you in advance!

5 REPLIES 5
Amel NASRI
ST Employee

Hi @MCris.4​ ,

In the current situation, I believe that you are meeting the same conditions as the limitation I2C1 with SPI1 remapped and used in master mode described in STM32F101x4/6, STM32F102x4/6, STM32F103x4/6 device errata.

The workaround provided there is:

  • Do not use SPI1 remapped in master mode and I2C1 together.
  • When using SPI1 remapped, the I2C1 clock must be disabled.

-Amel

To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.

MCris.4
Associate II

Hi @Amel NASRI​,

thank you so much for your reply.

I've tried to enable the I2C CLK before using the peripheral and disable it after that. But this does not working because after an power reset the function HAL_I2C_Master_Receive return an HAL_BUSY result.

__HAL_RCC_I2C1_CLK_ENABLE();
HAL_I2C_Master_Receive(....);
__HAL_RCC_I2C1_CLK_DISABLE();

I've also tried to initialize the peripheral before using it, but it still not working after a power reset due to the a fault raised while performing the __HAL_I2C_DISABLE(hi2c) macro on the HAL_I2C_Init() function.

HAL_I2C_Init(&_hi2c);
HAL_I2C_Master_Receive(&_hi2c, ...);
HAL_I2C_DeInit(&_hi2c);

Since the problem always rises when performing a power reset and working properly if I do a software reset, I think the issue may be related with the backup registers.

Any suggestion?

S.Ma
Principal

If I was facing this challenge, I would think creating a special transition function. I2C bus requires bus idle by default, which means sda and scl high. Slaves on the bus maybe out of whack when bus type changes. This happens when playing with some ST mems which SPI NSS is in fact a I2CSPI selector.

To switch from SPI to I2C:

Force SCK low.

Stop SPI perupheral clock (not SCK) to freeze to freeze time. Change MISO MOSI NSS then SCK. By bitbang send 18 stop bits to sync up slaves if SDA is low. Then make sure bus is idle. Activate I2C pins theb activate peripheral clock to make it alive.

Similarl method for switching back to SPI mode. Make sense?

MCris.4
Associate II

Hello @S.Ma​,

If I understood correctly, your solution is suitable for using the spi and the i2c on the same pins. However, I am using the I2C and SPI on different ports (I2C on SCL - PB8, I2C SDA - PB9, SPI on PB3-5 SCK, MISO, MOSI) . So I think this solution does not work for me.

S.Ma
Principal

In this case, it is a pure user code sw issue. If you meant both transmitting data at same time on different pins, and working when not simultaneously, this is probably because of bare metal implementation. If i want full background complex and autonomous peripherals in bare metal, i use an interrupt triggered state machine to build non dumb peripheral, including a sw fifo to queue data transactions. Requires some XP do try this.