2024-05-06 07:37 AM
Hi all,
I've been battling an I2C issue for a couple of weeks, been through so many forum posts, and have tried a number of things, now I'm looking for some help to figure out what I'm missing.
Problem Description:
Master I2C device triggers slave transmit on STM32F101vft6. Using HAL_I2C_Slave_Seq_Transmit_(IT|DMA), in the AddrCallback, the STM sends length, 2 bytes, then sends message, up to 400 bytes. Common case is 22-28 bytes. I2C Bus set for 100KHz, using clock stretch, master configured for up to 20ms clock stretch by the slave.
In some cases, the STM32 slave has ~1ms clock stretch, and then fails to send any data. Sometimes, it takes the clock low, and holds it there forever. The hi2c reports the XferSize is 400, and the XferCount is 398, implying 2 bytes have been sent, but the scope does not show data on the i2c bus, (trigger condition met, can see the Start, R, Ack).
Heavier use of the bus (increase number of messages/time) exacerbates the problem. Reducing the bus speed (100KHz -> 50KHz -> 25KHz -> 7.5KHz -> 5KHz -> 1KHz) improves reliability. Unfortunately, I had to reduce the clock to 1KHz to get rock solid behavior.
I have used 4 techniques for buffer management for transmit on the slave side, XMessageBuffer, osMessageQueue, critical section for handling a char[400], and lastly with a memcpy to the local buffer (current code). I’ve tried both _IT and _DMA methods.
I have also tried setting NVIC to make sure I2C interrupts had the highest priority (based on some reading I did, implying this could be an issue).
void HAL_I2C_AddrCallback(I2C_HandleTypeDef *hi2c, uint8_t transferDirection, uint16_t addrMatchCode)
{
if (hi2c->Instance == I2C2)
{
// HAL_GPIO_TogglePin(GPIOD, GPIO_PIN_15); // debug to scope intr timing
// Transfer direction is defined form the perspective of the *master*,
// ie TRANSMIT means the master wants to transmit and that we should receive
if (transferDirection == I2C_DIRECTION_TRANSMIT)
{
comm_receiving_length = true;
// Request 2 bytes for the overall message length
HAL_I2C_Slave_Sequential_Receive_IT(&hi2c2, comms_rx_buffer, 2, I2C_FIRST_FRAME);
}
else
{
HAL_GPIO_WritePin(COMM_INTR_GPIO_Port, COMM_INTR_Pin, GPIO_PIN_RESET);
UBaseType_t intStatus;
intStatus = taskENTER_CRITICAL_FROM_ISR();
HAL_StatusTypeDef status;
memcpy(send_buf, comms_tx_buffer, sizeof(comms_tx_buffer));
taskEXIT_CRITICAL_FROM_ISR(intStatus);
status = HAL_I2C_Slave_Seq_Transmit_DMA(&hi2c2, send_buf, sizeof(send_buf), I2C_LAST_FRAME);
// HAL_GPIO_TogglePin(GPIOD, GPIO_PIN_15); // debug to scope intr timing
if (OCTO_DEBUG)
{
if (HAL_OK != status)
{
Error_Handler();
}
}
}
}
}
If there's anything that would be useful to add in, please say so, I'll add it in.
2024-09-12 08:49 PM
Were you ever able to figure out why this was happening?