Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
I2C_IIC
STM32
中断
stm32 I2c 死循环
发布于 2023-12-22 10:39:23 浏览:691
订阅该版
求助,i2c硬件驱动程序不稳定,不知道该怎么解决了! 最近增加了i2c硬件中断的驱动程序,用200KHZ以下跑没问题,但是设置到400KHZ后,开机一段时间程序会卡在如下中断中持续触发,中断无法关闭: ```c void I2C1_EV_IRQHandler(void) { rt_interrupt_enter(); HAL_I2C_EV_IRQHandler(&hard_i2c_bus_obj[0].handle); rt_interrupt_leave(); } ``` 如下图片是400KH还未死循环时的波形 ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20231222/fba8150a78bf01916c74f7c49b09d190.png.webp) 如下图片时400KHZ死循环瞬间的波形 ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20231222/1c245b907615a3e7cc993c3cc01bedad.png) 如下是I2C句柄进入HAL_I2C_EV_IRQHandler库函数后内部的变量值 ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20231222/7b0baf4f37b26631598f6f7445a2888b.png.webp) I2C的SR1寄存器值为0x80,按照参考手册解释如下 ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20231222/84038bfaf2633133775db33ae81e936e.png.webp) 在HAL_I2C_EV_IRQHandler库函数内部进入I2C_MasterTransmit_BTF(hi2c) ```c /* BTF set -------------------------------------------------------------*/ else if ((I2C_CHECK_FLAG(sr1itflags, I2C_FLAG_BTF) != RESET) && (I2C_CHECK_IT_SOURCE(itsources, I2C_IT_EVT) != RESET)) { I2C_MasterTransmit_BTF(hi2c); } ``` 但是进入I2C_MasterTransmit_BTF内部后,if (hi2c->State == HAL_I2C_STATE_BUSY_TX)判断不成立,直接跳出,导致中断无限循环卡死(实际我现在是HAL_I2C_STATE_BUSY_RX,因为是读i2c的寄存器) ```c static void I2C_MasterTransmit_BTF(I2C_HandleTypeDef *hi2c) { /* Declaration of temporary variables to prevent undefined behavior of volatile usage */ uint32_t CurrentXferOptions = hi2c->XferOptions; if (hi2c->State == HAL_I2C_STATE_BUSY_TX) { if (hi2c->XferCount != 0U) { /* Write data to DR */ hi2c->Instance->DR = *hi2c->pBuffPtr; /* Increment Buffer pointer */ hi2c->pBuffPtr++; /* Update counter */ hi2c->XferCount--; } else { /* Call TxCpltCallback() directly if no stop mode is set */ if ((CurrentXferOptions != I2C_FIRST_AND_LAST_FRAME) && (CurrentXferOptions != I2C_LAST_FRAME) && (CurrentXferOptions != I2C_NO_OPTION_FRAME)) { __HAL_I2C_DISABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR); hi2c->PreviousState = I2C_STATE_MASTER_BUSY_TX; hi2c->Mode = HAL_I2C_MODE_NONE; hi2c->State = HAL_I2C_STATE_READY; #if (USE_HAL_I2C_REGISTER_CALLBACKS == 1) hi2c->MasterTxCpltCallback(hi2c); #else HAL_I2C_MasterTxCpltCallback(hi2c); #endif /* USE_HAL_I2C_REGISTER_CALLBACKS */ } else /* Generate Stop condition then Call TxCpltCallback() */ { /* Disable EVT, BUF and ERR interrupt */ __HAL_I2C_DISABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR); /* Generate Stop */ SET_BIT(hi2c->Instance->CR1, I2C_CR1_STOP); hi2c->PreviousState = I2C_STATE_NONE; hi2c->State = HAL_I2C_STATE_READY; if (hi2c->Mode == HAL_I2C_MODE_MEM) { hi2c->Mode = HAL_I2C_MODE_NONE; #if (USE_HAL_I2C_REGISTER_CALLBACKS == 1) hi2c->MemTxCpltCallback(hi2c); #else HAL_I2C_MemTxCpltCallback(hi2c); #endif /* USE_HAL_I2C_REGISTER_CALLBACKS */ } else { hi2c->Mode = HAL_I2C_MODE_NONE; #if (USE_HAL_I2C_REGISTER_CALLBACKS == 1) hi2c->MasterTxCpltCallback(hi2c); #else HAL_I2C_MasterTxCpltCallback(hi2c); #endif /* USE_HAL_I2C_REGISTER_CALLBACKS */ } } } } } ``` 贴出我写的硬件I2c的驱动程序原代码如下: ```c /* * Copyright (c) 2006-2021, RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date Author Notes * 2023-12-17 zzzyy the first version */ #include
#include "drv_hard_i2c.h" #include "drv_config.h" #include
#include
#ifdef BSP_USING_HARD_I2C //#define DRV_DEBUG #define LOG_TAG "drv.hwi2c" #include
#if !defined(BSP_USING_HARD_I2C1) && !defined(BSP_USING_HARD_I2C2) && !defined(BSP_USING_HARD_I2C3) && !defined(BSP_USING_HARD_I2C4) #error "Please define at least one BSP_USING_I2Cx" #endif /* stm32 config class */ struct stm32_hard_i2c_config { I2C_TypeDef *Instance; /* i2c bus name */ const char *bus_name; /* i2c bus name */ rt_uint8_t scl; rt_uint8_t sda; }; static struct stm32_hard_i2c_config hard_i2c_config[] = { #ifdef BSP_USING_HARD_I2C1 HARD_I2C_CONFIG(1), #endif #ifdef BSP_USING_HARD_I2C2 HARD_I2C_CONFIG(2), #endif #ifdef BSP_USING_HARD_I2C3 HARD_I2C_CONFIG(3), #endif #ifdef BSP_USING_HARD_I2C4 HARD_I2C_CONFIG(4), #endif }; /* stm32 i2c dirver class */ typedef rt_err_t (*configure)(struct rt_i2c_bus_device *device, struct rt_i2c_configuration configuration); struct stm32_i2c { I2C_HandleTypeDef handle; /* i2c handle */ const struct stm32_hard_i2c_config *config; struct rt_i2c_configuration cfg; struct rt_i2c_bus_device i2c_bus; configure configure; rt_sem_t tx_notice; /*发送完成信号量*/ rt_sem_t rx_notice; /*接收完成信号量*/ rt_uint8_t bus_busy_flag; /*总线忙标志*/ }; static struct stm32_i2c hard_i2c_bus_obj[sizeof(hard_i2c_config) / sizeof(hard_i2c_config[0])] = {0}; static rt_err_t stm32_hard_i2c_init(struct stm32_i2c *i2c_drv) { RT_ASSERT(i2c_drv != RT_NULL); I2C_HandleTypeDef *i2c_handle = &i2c_drv->handle; struct rt_i2c_configuration *cfg = &i2c_drv->cfg; i2c_handle->Init.ClockSpeed = cfg->speed ; if (cfg->speed > RT_I2C_SPEED_400KHZ) { i2c_handle->Init.ClockSpeed = RT_I2C_SPEED_400KHZ; } i2c_handle->Init.DutyCycle = I2C_DUTYCYCLE_2; i2c_handle->Init.OwnAddress1 = 0; i2c_handle->Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT; i2c_handle->Init.DualAddressMode = I2C_DUALADDRESS_DISABLE; i2c_handle->Init.OwnAddress2 = 0; i2c_handle->Init.GeneralCallMode = I2C_GENERALCALL_DISABLE; i2c_handle->Init.NoStretchMode = I2C_NOSTRETCH_DISABLE; LOG_D("sys freq: %d, i2c freq: %d", HAL_RCC_GetSysClockFreq(), i2c_handle->Init.ClockSpeed); if (HAL_I2C_Init(i2c_handle) != HAL_OK) { return RT_EIO; } LOG_D("%s init done", i2c_drv->config->bus_name); return RT_EOK; } static rt_err_t hard_i2c_configure(struct rt_i2c_bus_device *device, struct rt_i2c_configuration configuration) { RT_ASSERT(device != RT_NULL); struct stm32_i2c *i2c_drv = rt_container_of(device, struct stm32_i2c, i2c_bus); i2c_drv->cfg = configuration; return stm32_hard_i2c_init(i2c_drv); } /** * if i2c is locked, this function will unlock it * * @param stm32 config class * * @return RT_EOK indicates successful unlock. */ static rt_err_t stm32_i2c_bus_unlock(struct stm32_i2c *i2c_drv) { rt_int32_t i = 0; rt_err_t ret = RT_EOK; I2C_HandleTypeDef *handle = &i2c_drv->handle; const struct stm32_hard_i2c_config *config = i2c_drv->config; // rt_enter_critical(); if (PIN_HIGH == rt_pin_read(config->sda)) { goto __exit; } rt_pin_mode(config->scl, PIN_MODE_OUTPUT_OD); rt_pin_mode(config->sda, PIN_MODE_OUTPUT_OD); rt_pin_write(config->sda, PIN_HIGH); /*发送9次clk*/ while (i++ < 9) { rt_pin_write(config->scl, PIN_HIGH); rt_hw_us_delay(20); rt_pin_write(config->scl, PIN_LOW); rt_hw_us_delay(20); } if (PIN_LOW == rt_pin_read(config->sda)) { ret = -RT_EIO; } else { /*成功检测到ACK,发送停止*/ rt_pin_write(config->sda, PIN_LOW); rt_hw_us_delay(1); rt_pin_write(config->scl, PIN_HIGH); rt_hw_us_delay(10); rt_pin_write(config->sda, PIN_HIGH); } /*硬件初始化*/ __exit: HAL_I2C_MspInit(handle); // rt_exit_critical(); return ret; } static rt_err_t stm32_i2c_rst_busy(struct rt_i2c_bus_device *bus) { rt_err_t ret = RT_EOK; struct stm32_i2c *i2c_drv = rt_container_of(bus, struct stm32_i2c, i2c_bus); I2C_HandleTypeDef *handle = &i2c_drv->handle; rt_enter_critical(); /*有问题,没弄明白原因*/ /* Disable EVT and ERR interrupt */ // __HAL_I2C_DISABLE_IT(handle, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR); // HAL_I2C_DeInit(handle); /*禁用i2c*/ __HAL_I2C_DISABLE(handle); if (__HAL_I2C_GET_FLAG(handle, I2C_FLAG_BUSY) != RESET) { i2c_drv->bus_busy_flag = 1; ret = stm32_i2c_bus_unlock(i2c_drv); if (ret != RT_EOK) { goto __exit; } } /*复位控制器*/ handle->Instance->CR1 |= I2C_CR1_SWRST; handle->Instance->CR1 &= ~I2C_CR1_SWRST; if (__HAL_I2C_GET_FLAG(handle, I2C_FLAG_BUSY) != RESET) { ret = -RT_EIO; goto __exit; } i2c_drv->bus_busy_flag = 0; __exit: /*软复位i2c控制器后,必须重新初始化*/ HAL_I2C_Init(handle); rt_exit_critical(); return ret; } static rt_size_t i2c_hard_xfer(struct rt_i2c_bus_device *bus, struct rt_i2c_msg msgs[], rt_uint32_t num) { struct rt_i2c_msg *msg; struct stm32_i2c *i2c_drv = rt_container_of(bus, struct stm32_i2c, i2c_bus); I2C_HandleTypeDef *handle = &i2c_drv->handle; rt_int32_t ret; HAL_StatusTypeDef hal_status; rt_uint8_t rst_flag = 0; if (num == 0) return 0; if (i2c_drv->bus_busy_flag) { __i2c_start: ret = stm32_i2c_rst_busy(bus); if (ret != RT_EOK) { goto __exit; } rst_flag = 1; } if (num == 1) { msg = &msgs[0]; if (msg->flags & RT_I2C_RD) { hal_status = HAL_I2C_Master_Receive_IT(handle, (msg->addr << 1), msg->buf, msg->len); if (hal_status != HAL_OK) { if (rst_flag) { ret = -hal_status; goto __exit; } /*复位重试*/ goto __i2c_start; } ret = rt_sem_take(i2c_drv->rx_notice, (10 * msg->len)); if (ret != RT_EOK) { HAL_I2C_Master_Abort_IT(handle, msg->addr << 1); goto __exit; } } else { hal_status = HAL_I2C_Master_Transmit_IT(handle, msg->addr << 1, msg->buf, msg->len); if (hal_status != HAL_OK) { if (rst_flag) { ret = -hal_status; goto __exit; } /*复位重试*/ goto __i2c_start; } ret = rt_sem_take(i2c_drv->tx_notice, (10 * msg->len)); if (ret != RT_EOK) { HAL_I2C_Master_Abort_IT(handle, msg->addr << 1); goto __exit; } } ret = 1; } else if (num == 2) { msg = &msgs[0]; if (((msgs[0].flags & RT_I2C_WR) == RT_I2C_WR) &&((msgs[1].flags & RT_I2C_RD) == RT_I2C_RD)) { hal_status = HAL_I2C_Mem_Read_IT(handle, (msg->addr << 1), *(msg->buf), I2C_MEMADD_SIZE_8BIT, msg[1].buf, msg[1].len); if (hal_status != HAL_OK) { if (rst_flag) { ret = -hal_status; goto __exit; } /*复位重试*/ goto __i2c_start; } ret = rt_sem_take(i2c_drv->rx_notice, (10 * msg->len)); if (ret != RT_EOK) { ; goto __exit; } } else { hal_status = HAL_I2C_Mem_Write_IT(handle, msg->addr << 1, *(msg->buf), I2C_MEMADD_SIZE_8BIT, msg[1].buf, msg[1].len); if (hal_status != HAL_OK) { if (rst_flag) { ret = -hal_status; goto __exit; } /*复位重试*/ goto __i2c_start; } ret = rt_sem_take(i2c_drv->tx_notice, (10 * msg->len)); if (ret != RT_EOK) { ; goto __exit; } } ret = 2; } else { ret = -RT_EINVAL; } return ret; __exit: return ret; } static const struct rt_i2c_bus_device_ops i2c_hard_bus_ops = { .master_xfer = i2c_hard_xfer, .slave_xfer = RT_NULL, .i2c_bus_control = RT_NULL, }; static int rt_hw_i2c_bus_init(void) { rt_err_t ret = RT_EOK; char str[RT_NAME_MAX*2] = ""; struct rt_i2c_configuration config ={0}; for (int i = 0; i < sizeof(hard_i2c_config) / sizeof(hard_i2c_config[0]); i++) { hard_i2c_bus_obj[i].config = &hard_i2c_config[i]; hard_i2c_bus_obj[i].handle.Instance = hard_i2c_config[i].Instance; hard_i2c_bus_obj[i].i2c_bus.ops = &i2c_hard_bus_ops; hard_i2c_bus_obj[i].configure = hard_i2c_configure; if (i==0) { #ifdef BSP_HARD_I2C1_SPEED config.speed = BSP_HARD_I2C1_SPEED; #else config.speed = RT_I2C_SPEED_100KHZ; #endif } else if(i == 1) { #ifdef BSP_HARD_I2C2_SPEED config.speed = BSP_HARD_I2C2_SPEED; #else config.speed = RT_I2C_SPEED_100KHZ; #endif } else { config.speed = RT_I2C_SPEED_100KHZ; } ret = hard_i2c_bus_obj[i].configure(&hard_i2c_bus_obj[i].i2c_bus,config); /*解锁*/ ret = stm32_i2c_bus_unlock(&hard_i2c_bus_obj[i]); RT_ASSERT(ret == RT_EOK); ret = rt_i2c_bus_device_register(&hard_i2c_bus_obj[i].i2c_bus,hard_i2c_bus_obj[i].config->bus_name); RT_ASSERT(ret == RT_EOK); LOG_D("%s bus init done", hard_i2c_bus_obj[i].config->bus_name); strcpy(str,hard_i2c_bus_obj[i].config->bus_name); strcat(str,"_tx"); hard_i2c_bus_obj[i].tx_notice = rt_sem_create(str, 0, RT_IPC_FLAG_FIFO); strcpy(str,hard_i2c_bus_obj[i].config->bus_name); strcat(str,"_rx"); hard_i2c_bus_obj[i].rx_notice = rt_sem_create(str, 0, RT_IPC_FLAG_FIFO); } return ret; } #ifdef BSP_USING_HARD_I2C1 void I2C1_EV_IRQHandler(void) { rt_interrupt_enter(); HAL_I2C_EV_IRQHandler(&hard_i2c_bus_obj[0].handle); rt_interrupt_leave(); } void I2C1_ER_IRQHandler(void) { rt_interrupt_enter(); HAL_I2C_ER_IRQHandler(&hard_i2c_bus_obj[0].handle); rt_interrupt_leave(); } #endif #ifdef BSP_USING_HARD_I2C2 void I2C2_EV_IRQHandler(void) { rt_interrupt_enter(); HAL_I2C_EV_IRQHandler(&hard_i2c_bus_obj[1].handle); rt_interrupt_leave(); } void I2C2_ER_IRQHandler(void) { rt_interrupt_enter(); HAL_I2C_ER_IRQHandler(&hard_i2c_bus_obj[1].handle); rt_interrupt_leave(); } #endif /*void HAL_I2C_ErrorCallback(I2C_HandleTypeDef *hi2c) { ; }*/ void HAL_I2C_MasterTxCpltCallback(I2C_HandleTypeDef *hi2c) { /* enter interrupt */ rt_interrupt_enter(); struct stm32_i2c *i2c_drv = rt_container_of(hi2c, struct stm32_i2c, handle); rt_sem_release(i2c_drv->tx_notice); /* leave interrupt */ rt_interrupt_leave(); } void HAL_I2C_MasterRxCpltCallback(I2C_HandleTypeDef *hi2c) { /* enter interrupt */ rt_interrupt_enter(); struct stm32_i2c *i2c_drv = rt_container_of(hi2c, struct stm32_i2c, handle); rt_sem_release(i2c_drv->rx_notice); /* leave interrupt */ rt_interrupt_leave(); } void HAL_I2C_MemTxCpltCallback(I2C_HandleTypeDef *hi2c) { /* enter interrupt */ rt_interrupt_enter(); struct stm32_i2c *i2c_drv = rt_container_of(hi2c, struct stm32_i2c, handle); rt_sem_release(i2c_drv->tx_notice); /* leave interrupt */ rt_interrupt_leave(); } void HAL_I2C_MemRxCpltCallback(I2C_HandleTypeDef *hi2c) { /* enter interrupt */ rt_interrupt_enter(); struct stm32_i2c *i2c_drv = rt_container_of(hi2c, struct stm32_i2c, handle); rt_sem_release(i2c_drv->rx_notice); /* leave interrupt */ rt_interrupt_leave(); } int rt_hw_i2c_init(void) { return rt_hw_i2c_bus_init(); } INIT_BOARD_EXPORT(rt_hw_i2c_init); #endif ``` 2024年1月4日更新: 问题已经解决,原因在于中断优先级。 我这个项目用到了uart1、uart2、i2c1和i2c2,以及几个外部输入中断,最终设置如下: 1. rt-thread默认把SysTick和PendSV优先级设置为0xFF,就是最低; 2. rt-thread默认把硬件定时器中断设置为3; 3. rt-thread默认外部输入中断设置为5; 4. rt-thread默认没有设置串口中断,那就是默认值0了,所以CubeMX中手动把两个uart设置为2; 5. i2c1和i2c2在CubeMx中分别设置为0和1(我的项目中不能设置成一致,要不依然存在中断优先的问题,为什么i2c1是0,那是因为i2c1是进行读和写了,i2c2只进行写,只有i2c1存在BTF标志位置1的问题); 这样,就不会发生i2c状态寄存器中BTF位提前置1导致死循环的问题了,系统始终优先处理i2c中断。 再次感谢评论区对我的帮助!
查看更多
oxlm
2024-01-01
这家伙很懒,什么也没写!
不知道你用的是不是早期的stm32的型号,没记错的话,早期的stm32硬件I2C有坑,得用软件I2C
3
个回答
默认排序
按发布时间排序
用RTT跑流水灯
2023-12-31
这家伙很懒,什么也没写!
可以用软件iic
CrazyH
2024-01-02
这家伙很懒,什么也没写!
i2c一般软件上
撰写答案
登录
注册新账号
关注者
0
被浏览
691
关于作者
不简单呀
这家伙很懒,什么也没写!
提问
4
回答
0
被采纳
0
关注TA
发私信
相关问题
1
NXP的I2C应该比ST的好用吧
2
Use of I2C device driver
3
关于I2C 驱动问题请教
4
我如何知道这个iic的io配置和我电路设计的是一致的?
5
I2C模拟读操作失败,不知道问什么进不去读函数
6
RTT的I2C有官方文档资料没有
7
求 STM32F103 IIC 自定义IO初始化 代码
8
报一个LPC4008代码中I2C的bug
9
RTOS IIC总线使用
10
关于在RTT中使用STM32 I2C的疑问
推荐文章
1
RT-Thread应用项目汇总
2
玩转RT-Thread系列教程
3
机器人操作系统 (ROS2) 和 RT-Thread 通信
4
国产MCU移植系列教程汇总,欢迎查看!
5
五分钟玩转RT-Thread新社区
6
【技术三千问】之《玩转ART-Pi》,看这篇就够了!干货汇总
7
关于STM32H7开发板上使用SDIO接口驱动SD卡挂载文件系统的问题总结
8
STM32的“GPU”——DMA2D实例详解
9
RT-Thread隐藏的宝藏之completion
10
【ART-PI】RT-Thread 开启RTC 与 Alarm组件
最新文章
1
【24嵌入式设计大赛】基于RT-Thread火星一号华为云平台储能监测管理系统
2
RVBacktrace RISC-V极简栈回溯组件
3
一文教你如何在VSCODE中搭建RT-Thread开发环境
4
分享第一次PR的经历
5
EtherCAT EOE移植及上手说明
热门标签
RT-Thread Studio
串口
Env
LWIP
SPI
AT
Bootloader
Hardfault
CAN总线
ART-Pi
FinSH
USB
文件系统
DMA
RT-Thread
SCons
RT-Thread Nano
线程
MQTT
STM32
RTC
FAL
rt-smart
ESP8266
I2C_IIC
ota在线升级
WIZnet_W5500
UART
flash
packages_软件包
cubemx
PWM
freemodbus
BSP
潘多拉开发板_Pandora
定时器
ADC
中断
flashDB
socket
Debug
GD32
编译报错
msh
keil_MDK
at_device
rt_mq_消息队列_msg_queue
ulog
C++_cpp
SFUD
本月问答贡献
出出啊
1512
个答案
341
次被采纳
小小李sunny
1437
个答案
289
次被采纳
张世争
774
个答案
167
次被采纳
crystal266
546
个答案
161
次被采纳
whj467467222
1222
个答案
148
次被采纳
本月文章贡献
出出啊
1
篇文章
2
次点赞
小小李sunny
1
篇文章
1
次点赞
张世争
1
篇文章
2
次点赞
crystal266
2
篇文章
1
次点赞
whj467467222
2
篇文章
2
次点赞
回到
顶部
发布
问题
分享
好友
手机
浏览
扫码手机浏览
投诉
建议
回到
底部