2020-07-18 07:03 AM
Hello I am trying to learn I2C communication between 2 STM32F103C8 MCUs. MCU1 acts as the master and MCU2 acts as the slave. I am using CubeMX to configure the settings however I could not establish a link between the 2 MCUs. What I wanted to happen is that once I toggle a button connected to MCU1, the LED controlled by MCU2 should be enabled.
May I ask for your advice on the code below.
Master MCU1 code:
//Enable Button_LED1 and transmit 0xFF data. 0x5A (0b01011010) Slave + Write (0)
if(HAL_GPIO_ReadPin(BUTTON_LED1_GPIO_Port, BUTTON_LED1_Pin))
{
Buffer_I2C[0] = 0xFF;
HAL_I2C_Master_Transmit(&hi2c1, 0x5A, Buffer_I2C, 1, 10);
}
//Disable Button_LED1 and transmit 0x00 data
else
{
Buffer_I2C[0] = 0x00;
HAL_I2C_Master_Transmit(&hi2c1, 0x5A, Buffer_I2C, 1, 10);
}
Slave MCU2 code:
hi2c1.Instance = I2C1;
hi2c1.Init.ClockSpeed = 100000;
hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2;
hi2c1.Init.OwnAddress1 = 0x5B; //Slave + Read (1)
hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
hi2c1.Init.OwnAddress2 = 0;
hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
if (HAL_I2C_Init(&hi2c1) != HAL_OK)
{
HAL_I2C_Slave_Receive(&hi2c1, Buffer_I2C, 1, 10);
uint8_t data = Buffer_I2C[0];
switch(data)
{
case 0xFF:
HAL_GPIO_WritePin(LED2_GPIO_Port, LED2_Pin, GPIO_PIN_SET);
break;
case 0x00:
HAL_GPIO_WritePin(LED2_GPIO_Port, LED2_Pin, GPIO_PIN_RESET);
break;
default:
break;
}
}
:
2020-07-18 07:08 AM
The timeout for HAL_I2C_Slave_Receive is pretty short. Try with a longer timeout, even HAL_MAX_DELAY for a blocking read. And: check the return code.
2020-07-18 07:17 AM
Thank you for the hint. I tried changing the timeout longer to 50 but still it is not working. What is wrong with the return code?
2020-07-18 08:21 AM
Is this your actual code?
if yes in you slave code your if statement should be
if (HAL_I2C_Init(&hi2c1) == HAL_OK)
2020-07-18 09:09 AM
Sorry I forgot to tell that the If statement of the Slave is in the while(1) loop.
I did not change the line you mentioned as this was generated by CubeMX:
if (HAL_I2C_Init(&hi2c1) != HAL_OK)
Slave MCU2 code:
hi2c1.Instance = I2C1;
hi2c1.Init.ClockSpeed = 100000;
hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2;
hi2c1.Init.OwnAddress1 = 0x5B; //Slave + Read (1)
hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
hi2c1.Init.OwnAddress2 = 0;
hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
if (HAL_I2C_Init(&hi2c1) != HAL_OK)
while(1)
{
HAL_I2C_Slave_Receive(&hi2c1, Buffer_I2C, 1, 10);
uint8_t data = Buffer_I2C[0];
switch(data)
{
case 0xFF:
HAL_GPIO_WritePin(LED2_GPIO_Port, LED2_Pin, GPIO_PIN_SET);
break;
case 0x00:
HAL_GPIO_WritePin(LED2_GPIO_Port, LED2_Pin, GPIO_PIN_RESET);
break;
default:
break;
}
}
}
2020-07-18 09:12 AM
You don't check it.
2020-07-18 09:34 AM
I tried changing that line as you suggested but still not working.
2020-07-18 01:17 PM
> as this was generated by CubeMX:
Are you sure you didn't delete a call to Error_Handler? The code you posted looks edited from what CubeMX generates.
> HAL_I2C_Slave_Receive(&hi2c1, Buffer_I2C, 1, 10);
You should be looking at the return value and only processing the byte if it was actually received, as opposed to a timeout happening.
2020-07-18 08:33 PM
No I did not edit anything else after I generated the code only the address of the slave. Thanks for the suggestions.
2021-12-08 03:26 PM
In master , you mentioned the slave address as 0x5A " HAL_I2C_Master_Transmit(&hi2c1, 0x5A, Buffer_I2C, 1, 10); "
In Slave , you mentioned the slave address as 0x5B " hi2c1.Init.OwnAddress1 = 0x5B; "
Actually, API will call 7-bit address and based on the Transmit & Receive functions, it will automatically append the R/nW bit. Yes, API "ll do it for you.
Just declare the " 7-bit address with right shift of 1 bit " throughout the program.