STM32F103C8用Embassy与24C16N EEPROM通信失败但stm32f1xx_hal正常
排查Embassy与24C16N EEPROM通信失败的关键点
1. 核对I2C时钟与时序配置差异
stm32f1xx_hal的阻塞I2C可能默认适配了24C16N的时序,而Embassy的默认配置可能存在偏差:
- 24C16N支持的最高I2C时钟为100kHz(标准模式),部分场景下400kHz快速模式也可工作,但需严格匹配时序参数。
- Embassy初始化I2C时,需显式指定时钟速率和占空比,示例:
let i2c = embassy_stm32::i2c::I2c::new( peripherals.I2C1, scl, sda, embassy_stm32::i2c::Config::default() .frequency(100_000.Hz()) .duty_cycle(embassy_stm32::i2c::DutyCycle::Ratio2to1), // 标准模式常用2:1占空比 );
- 检查HAL中I2C的时钟源(如APB1时钟频率),确认Embassy的系统时钟配置与HAL一致,外设时钟错误会直接导致通信失败。
2. 确认引脚模式配置
STM32F1的I2C引脚需配置为开漏输出+上拉(硬件上拉或内部上拉):
- stm32f1xx_hal可能自动将引脚设置为
OpenDrain模式,而Embassy需要显式指定:
let scl = peripherals.PB6.into_open_drain_output(); let sda = peripherals.PB7.into_open_drain_output();
- 若依赖内部上拉,需在引脚配置中添加
pull_up():
let scl = peripherals.PB6.into_open_drain_output().pull_up(); let sda = peripherals.PB7.into_open_drain_output().pull_up();
3. 检查设备地址的处理方式
24C16N的设备地址格式为1010 A2 A1 A0 R/W,注意不同框架的地址处理差异:
- stm32f1xx_hal和Embassy均要求传入7位地址(不含R/W位),驱动会自动添加读写位。例如A2/A1/A0均为0时,正确的7位地址是
0b1010000(十进制80),不要错误传入包含R/W位的8位地址。
4. 验证Embassy阻塞API的调度器初始化
使用Embassy的阻塞I2C API时,必须确保调度器已正确初始化:
- 需在代码开头初始化Embassy执行器,示例:
#[embassy_executor::main] async fn main(spawner: embassy_executor::Spawner) { let p = embassy_stm32::init(Default::default()); // 后续I2C初始化与操作代码 }
- 未初始化调度器会导致阻塞API因无法获取执行权而超时。
5. 排查Embassy STM32F1 I2C驱动的硬件初始化
部分版本的Embassy对STM32F1的I2C外设初始化可能存在遗漏:
- 确认I2C外设时钟已开启(Embassy的
I2c::new通常会自动处理,但可通过寄存器RCC->APB1ENR手动验证); - 尝试更新Embassy到最新稳定版,修复已知的驱动bug。
6. 抓波形对比HAL与Embassy的通信差异
用逻辑分析仪抓取两种方案下的I2C波形:
- 对比起始信号、地址帧、ACK信号的差异;
- 若Embassy发出起始信号后无ACK,说明设备未响应,大概率是地址或时序问题;
- 若波形无起始信号,说明I2C外设未正确初始化。
内容的提问来源于stack exchange,提问作者MrPashaPG
相关产品推荐
相关产品推荐

