I2C slave on a STM32F030T4P6 with HAL callbacks not working
I could really need some help how to get a STM32F030T4P6 to act as a i2c slave and receive a byte of data
I've spend so much time in the past week trying to solve this problem, but no progress at all
The final code must act as four PCF8574 port expanders and save the received byte in a common array with one index for each of the four PCF8574 addresses.
Why?.... Because it is a very easy way of getting some data from Home Assistant, via EsPHome into the MCU for further usage
I need to use these 4 bytes to create some serial pulse trains thet will control some relay modules that is using a special protocol.
I created a simulator to generate the I2C traffic, and it sends a write to the 4 I2C addresses with a delay of 2 seconds between packages, and then sends a read to the same 4 i2c adresses every 2 seconds, and then it starts over again
Currently my code only listen on one I2C address 0x20, and I can see, with a logic analyzer, that the STM32 sends ack both after an read and a write from master (Simulator), so it seems like that part is ok
But I only get an ack after the data on the first I2C write after a reset from the slave.
But the slave keeps sending ack after the address matches
If I enable clock stretching on the slave, then the slave keeps pulling the clk-line down.
Disabling clock stretching gives the behavior above, where the slave seems to be waiting for something.
Here's my callback I'm using:
(It looks like this type of MCU needs to use a ISR read followed by a read from RXDR to reset the interrupt flag)
void HAL_I2C_SlaveRxCpltCallback(I2C_HandleTypeDef *hi2c)
{
uint32_t devAddr = hi2c->Instance->ISR;
// Extract the matched address (7 bits) from the ISR
devAddr = (devAddr >> 16) & 0x7F; // Shift and mask to get 7-bit address
// Update the global last received address
lastReceivedAddress = (uint8_t)devAddr;
// Read the received byte from the data register
uint8_t receivedByte = hi2c->Instance->RXDR;
// Store the received byte based on the matched address
if (lastReceivedAddress == I2C_ADDRESS_1)
{
dataArray[0] = receivedByte; // Store data for Address 1 (0x20)
}
else if (lastReceivedAddress == I2C_ADDRESS_2)
{
dataArray[1] = receivedByte; // Store data for Address 2 (0x21)
}
else if (lastReceivedAddress == I2C_ADDRESS_3)
{
dataArray[2] = receivedByte; // Store data for Address 3 (0x22)
}
else if (lastReceivedAddress == I2C_ADDRESS_4)
{
dataArray[3] = receivedByte; // Store data for Address 4 (0x23)
}
// Re-enable slave reception for the next byte
HAL_I2C_Slave_Receive_IT(hi2c, (uint8_t *)dataArray, 1);
}
And in main:
// Enable i2c listening for i2c number 1
if(HAL_I2C_EnableListen_IT(&hi2c1) != HAL_OK)
{
/* Transfer error in reception process */
Error_Handler();
}
// Start listening in slave mode for data reception
HAL_I2C_Slave_Receive_IT(&hi2c1, (uint8_t *)dataArray, 1);
I've tried all I can imagine to get this i2c slave code working, like using the sequential Rx callback instead, with all kind of combinations of the FIRST / LAST etc, but I get the same result
What am I missing?
Or have I completely misunderstood how to use I2C in HAL ?
Br Steen


