2023-05-23 02:32 AM
Hi, I want to implement an I2C slave with a STM32L476 micro that basically behaves like a memory. Therefore it must respond to another micro which executes the HAL_I2C_Mem_Write() and HAL_I2C_Mem_Read() operations to this slave.
Searching on the internet I came to write this code and it seems to work.
void HAL_I2C_SlaveRxCpltCallback(I2C_HandleTypeDef *hi2c) {
printf("--> DEBUG: Write [%02X - %02X - %02X]\r\n", i2c_rx_buffer[0],
i2c_rx_buffer[1], i2c_rx_buffer[2]);
}
void HAL_I2C_AddrCallback(I2C_HandleTypeDef *hi2c, uint8_t TransferDirection, uint16_t AddrMatchCode) {
if (TransferDirection == 0) {
memset(i2c_rx_buffer, 0x00, MAX_I2C_RX_LEN);
if (HAL_I2C_Slave_Seq_Receive_IT(EXT_I2C, i2c_rx_buffer, MAX_I2C_RX_LEN, I2C_FIRST_AND_LAST_FRAME) != HAL_OK) {
Error_Handler();
}
} else {
printf("--> Read \r\n");
i2c_tx_buffer[0] = 0xFF;
if (HAL_I2C_Slave_Seq_Transmit_IT(EXT_I2C, i2c_tx_buffer, MAX_I2C_RX_LEN, I2C_FIRST_AND_LAST_FRAME) != HAL_OK) {
Error_Handler();
}
}
}
void HAL_I2C_ListenCpltCallback(I2C_HandleTypeDef *hi2c) {
if(HAL_I2C_EnableListen_IT(EXT_I2C) != HAL_OK) {
printf("********************** ERROR START LISTEN I2C\r\n");
Error_Handler();
}
}
void HAL_I2C_ErrorCallback(I2C_HandleTypeDef *hi2c) {
printf("HAL_I2C_ErrorCallback\r\n");
}
But now I have two problems:
1 - How do I deal with the fact that I don't know how many bytes will be written, since I don't know how long the packet that the master sends will be, what number should I put in the HAL_I2C_Slave_Seq_Receive_IT function. I tried to make a very large buffer, but if the master sends a variable number of bytes the HAL_I2C_ErrorCallback is always called.
How can I handle receiving a variable number of bytes?
2 - During read operations, the master first sends the address it wants to read from, but like my code, how do I see this address? Before doing the HAL_I2C_Slave_Seq_Transmit_IT, I should know which address the master wants to read, but I don't understand how to do it.
Can anyone help me, thanks.
2023-05-23 03:21 AM
Hello @FMass.1 ,
1.To handle receiving a number of bytes, you can try :
/* Size of Reception buffer */
#define RXBUFFERSIZE (COUNTOF(RxBuffer) - 1)
/* Exported macro ------------------------------------------------------------*/
#define COUNTOF(__BUFFER__) (sizeof(__BUFFER__) / sizeof(*(__BUFFER__)))
2.To determine the address that the master STM32L476 wants to read from during an I2C read operation, you can use the HAL_I2C_AddrCallback() function.
// Define a global variable to store the address
uint16_t slaveAddress;
// Implement the HAL I2C Address Callback
void HAL_I2C_AddrCallback(I2C_HandleTypeDef *hi2c, uint8_t TransferDirection, uint16_t AddrMatchCode)
{
if (TransferDirection == I2C_DIRECTION_RECEIVE)
{
// Save the received address
slaveAddress = AddrMatchCode;
}
}
Hope I helped you!
Foued
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.
2023-05-23 05:44 AM
2 . Regarding the second question: OK. As soon as I'm in the lab I'll do the test, but I think it's the solution I was looking for.
For the first one, maybe I explained myself badly, I know how big the buffer is; I declared that buffer in main.c and MAX_I2C_RX_LEN is also a define I made. (In the specific case it is 10)
I try to rephrase my question with an example: When the master tries to write something, he calls the
HAL_I2C_Mem_Write (I2C_HandleTypeDef * hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t * pData, uint16_t Size, uint32_t Timeout);
function or a similar function, as you can see in this function the uint16_t Size value is inserted which is the size of the packet being sent. The question is, how does the slave read exactly that many bytes.
In my example, as I said, MAX_I2C_RX_LEN is 10, but it's a number that I put because I know it's the maximum bytes in my case the master will send.
But the master could also send shorter packets, for example he could send only 2 or 3 bytes, in all those cases HAL_I2C_ErrorCallback is always called and HAL_I2C_SlaveRxCpltCallback is never called.
How do I get the HAL_I2C_SlaveRxCpltCallback to be called even when the master sends less than 10 bytes, or anyway less of the max buffer size?
I also have another program that I have to make soon, in which the master can send packets of variable length between 3 bytes and 64 bytes, how can I handle situations like these?
2023-05-23 06:42 AM
Yes ok, I understood that there was something that didn't happen with my code, but on all the examples I find on the internet I see that there is always this problem. The number of bytes that the master sends is always indicated.
The only thing I found, is a post that says to use the error cabblack as if it were a HAL_I2C_SlaveRxCpltCallback and ignore the errors, it still seems to me an incorrect way to do.
Can you tell me how to make an I2C slave, which can accept a variable number of bytes from the master?
2023-05-23 07:05 AM
you can just prepare the size of reception buffer before the reception
/* Size of Reception buffer */
#define RXBUFFERSIZE (COUNTOF(RxBuffer) - 1)
/* Exported macro ------------------------------------------------------------*/
#define COUNTOF(__BUFFER__) (sizeof(__BUFFER__) / sizeof(*(__BUFFER__)))
Foued
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.
2023-05-23 08:34 AM
Excuse me, but if I don't know how many bytes the master will send, how can I prepare the buffer?
Maybe in the first transfer the master could send 20 bytes, then in the second it could send 2 bytes, in the third 5 bytes and so on; not knowing how many bytes it will send, how can I prepare the buffer before receiving?
2023-11-18 07:12 AM
only way to solve that problem is send a byte or bytes indicating how many bytes master will transmit to the slave....