[英]STM32 HAL I2C is returning OVR (overrun/under-run) error when using an interrupt driven approach
我正在尝试实现一个中断驱动的I2C从设备,该设备可以随时准备在STM32L051上接收(传输时除外)。 问题是我一直在HAL_I2C_ErrorCallback中收到HAL_I2C_ERROR_OVR错误。 以下代码仅是示例,并且配置为接收3字节消息并以单字节状态进行响应。 一旦主机发送,运行此代码将触发OVR错误,然后似乎连续触发I2C1_IRQHandler,从而占用其他操作。 从属不能使用拉伸,因此我已禁用它,如下面的代码所示。 我对HAL相当陌生,并且大多数时候都将STM32Fxx系列与std外设库一起使用。 我已经审查了已发布的示例,甚至将其中的一些示例复制到了我更复杂的代码库中,仅得到相同的OVR错误。 你们有任何建议/建议/等吗? 可以将我推向可行的解决方案?
系统时钟速度:16MHz
I2C总线速度:10KHz
谢谢。
//**** Slave Rx/Tx ****//
int main(void)
{
/* USER CODE BEGIN 1 */
int responseSize = 1;
int bytesToReceive = 3;
bool error = false;
/* USER CODE END 1 */
/* MCU Configuration----------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* Configure the system clock */
SystemClock_Config();
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_I2C1_Init();
/* Initialize interrupts */
MX_NVIC_Init();
i2c_response[0] = 0x01;
responseSize = 1;
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
//**** Slave Rx/Tx Interrupt based ****//
if(slaveRxCallbackTriggered)
{
slaveRxCallbackTriggered = false;
if(responseSize > 0)
{
if(!IOModule_TransmitToMaster(i2c_response,responseSize))
{
error = true;
}
}
IOModule_ReceiveFromMaster(bytesToReceive);
}
else
IOModule_ReceiveFromMaster(bytesToReceive);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
/*------------------------------------------------------------------------------
I2C Receive data from master
*------------------------------------------------------------------------------*/
bool IOModule_ReceiveFromMaster(int numberOfBytes)
{
bool result = false;
if(HAL_I2C_GetState(&hi2c1) == HAL_I2C_STATE_READY)
{
HAL_StatusTypeDef status = HAL_I2C_Slave_Receive_IT(&hi2c1, (uint8_t *)i2c_rx_array, numberOfBytes);
if(status == HAL_OK)
{
result = true;
}
}
return result;
}
/*------------------------------------------------------------------------------
I2C Transmit data to master
*------------------------------------------------------------------------------*/
bool IOModule_TransmitToMaster(uint8_t txBuffer[], int bufferSize)
{
bool result = false;
while (HAL_I2C_GetState(&hi2c1) != HAL_I2C_STATE_READY)
{
}
HAL_StatusTypeDef status = HAL_I2C_Slave_Transmit(&hi2c1, (uint8_t*)txBuffer, bufferSize, 10000);
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_11,GPIO_PIN_RESET);
if(status == HAL_OK)
{
result = true;
}
return result;
}
/*------------------------------------------------------------------------------
I2C Slave Rx Complete Callback
*------------------------------------------------------------------------------*/
void HAL_I2C_SlaveRxCpltCallback(I2C_HandleTypeDef *I2CxHandle)
{
slaveRxCallbackTriggered = true;
}
/*------------------------------------------------------------------------------
I2C Error Callback
*------------------------------------------------------------------------------*/
void HAL_I2C_ErrorCallback(I2C_HandleTypeDef *hi2c)
{
lastErrorCode = HAL_I2C_GetError(&hi2c1);
}
//I2C1 init
void MX_I2C1_Init(void)
{
hi2c1.Instance = I2C1;
hi2c1.Init.Timing = 0x000006C5;
hi2c1.Init.OwnAddress1 = 0x24;
hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
hi2c1.Init.OwnAddress2 = 0;
hi2c1.Init.OwnAddress2Masks = I2C_OA2_NOMASK;
hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_ENABLE;
HAL_I2C_Init(&hi2c1);
/**Configure Analogue filter
*/
HAL_I2CEx_ConfigAnalogFilter(&hi2c1, I2C_ANALOGFILTER_ENABLE);
}
void HAL_I2C_MspInit(I2C_HandleTypeDef* hi2c)
{
GPIO_InitTypeDef GPIO_InitStruct;
if(hi2c->Instance==I2C1)
{
/**I2C1 GPIO Configuration
PB6 ------> I2C1_SCL
PB7 ------> I2C1_SDA
*/
GPIO_InitStruct.Pin = GPIO_PIN_6|GPIO_PIN_7;
GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF1_I2C1;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
/* Peripheral clock enable */
__HAL_RCC_I2C1_CLK_ENABLE();
}
}
主Tx / Rx
int main(void)
{
//**** Master Tx/Rx ****//
ioModule_response[0] = 0xA0;
ioModule_response[1] = 0x01;
ioModule_response[2] = 0xE3;
while(1)
{
if(HAL_I2C_Master_Transmit(&hi2c1, (uint16_t)0x24, (uint8_t*)ioModule_response, 3, 10000)== HAL_OK)
{
if(HAL_I2C_Master_Receive(&hi2c1, (uint16_t)0x24, (uint8_t *)i2c_rx_array, 1, 10000) != HAL_OK)
{
//Blink LED and Pause
LED_Show_StatusCode(2,false);
HAL_Delay(500);
}
else if(i2c_rx_array[0] != 1)
{
//Blink LED and Pause
LED_Show_StatusCode(3,false);
HAL_Delay(500);
}
}
}
}
这是STM32Cube MX生成的IRQ处理程序。
void I2C1_IRQHandler(void)
{
/* USER CODE BEGIN I2C1_IRQn 0 */
/* USER CODE END I2C1_IRQn 0 */
if (hi2c1.Instance->ISR & (I2C_FLAG_BERR | I2C_FLAG_ARLO | I2C_FLAG_OVR)) {
HAL_I2C_ER_IRQHandler(&hi2c1);
} else {
HAL_I2C_EV_IRQHandler(&hi2c1);
}
/* USER CODE BEGIN I2C1_IRQn 1 */
/* USER CODE END I2C1_IRQn 1 */
}
更新:我目前正在探索LL API,因为这看起来更像是我过去使用的标准外围设备库。
对我来说,解决方案是完全放弃HAL,并按照imbearr的建议使用LL API。 如前所述,我过去使用过STM32标准外围设备库,并且LL在许多方面都非常相似。
感谢imbearr的帮助。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.