cancel
Showing results for 
Search instead for 
Did you mean: 

I2C slave on a STM32F030T4P6 with HAL callbacks not working

SteenA
Associate II

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

4 REPLIES 4

Please see How to insert source code.

 


@SteenA wrote:

The final code must act as four PCF8574 port expanders ...

I created a simulator to generate the I2C traffic


Have you tested that your simulator actually works with real PCF8574s ?

gbm
Principal

Have you enabled the I2C interrupts in I2C configuration, NVIC tab?

My STM32 stuff on github - compact USB device stack and more: https://github.com/gbm-ii/gbmUSBdevice

@Andrew Neil 

 

Yes the simulator is working perfect with a real PCF8574, both read and write.

The ports of the PCF8574 are physically correctly set and read

And checking with the logic analyzer the protocol is exactly as expected and as written in the datasheet for the PCF8574

So far it is seems like that the simulator is not the problem

SteenA
Associate II

SteenA_0-1741081158493.png

@gbm 

After my current knowledge, I will say yes to the interrupt is correctly set in the NVIC
And as written my original post, the address match seems to work correctly and the STM32 slave is sending the correct ack back

But the next byte, the date, seems to get into some wait state after first data byte received.

But still according to the logic analyzer, the STM32 slave keeps responding to address match with an ack, and if I enable clock stretching then the slave keeps pulling the clock down to indicate that the Rx CPLT callback seems not to finish one way or another