常见坑
每一章对着一个报错或一个现象:先用最小的程序复现,再到源码里找它从哪一行来,最后给出修法和检查办法。机制在前面几部分讲过的,这里只链过去。复现分三种环境,每章都写明是哪一种:
- std:M2 Max、macOS 27、rustc 1.99.0;
- QEMU:QEMU 11.1.2
b-l475e-iot01a,embassy-stm32 打了一行补丁; - 只交叉编译:
thumbv7em-none-eabihf。
有几个坑是上游的问题,章里写明在哪个版本上复现、main 上修了没有。
- Undefined symbols: _embassy_time_now:用了
Timer却没有时间驱动,加第一个Timer时才报。 - symbol _embassy_time_now is already defined:两个驱动;跨 crate 时 macOS 的链接器不报错,悄悄选一个。
- the name TICK_HZ is defined multiple times:两个
tick-hz-*;只有库选了一个时不报错,频率却变了。 - No architecture selected for embassy-executor:没开
platform-*,报错还在说已经改名的arch-*。 - 开了 trace:Undefined symbols _embassy_trace*:
trace要求自己定义全部钩子,debug 和 release 缺的符号数不同。 - Busy - Too many instances of this task are already running:任务池满了,0.10.0 起在调用任务函数时就返回错误。
- SpawnToken instances may not be dropped:token 没交给
spawn;rustc 建议的let _ =照样 panic。 - #[task] 的报错:非
'static、泛型、impl Trait、17 个参数、省略的生命周期。 - 任务池比想的大:future 当参数传给 async fn 后翻倍。
- 一个任务忙等,其他任务全停:阻塞的
DelayNs、长计算,单执行器没有抢占。 - 几个任务等同一个 Channel / Signal 时 CPU 不睡:一个 waker 槽,互相挤掉、互相唤醒。
*mut ()cannot be shared between threads safely:NoopRawMutex放进static。- 中断里用 Noop / ThreadMode:
BorrowMutError、ThreadModeMutex can only be locked from thread mode。 - Found waker not created by the Embassy executor:
Timer在别的执行器或组合子里被 poll。 - 两个任务等一个 Signal,一个永远拿不到:
Signal只给一个人,要广播用Watch。 - PubSub 收到 Lagged:
publish_immediate挤掉慢订阅者的消息。 - select / with_timeout 输了,读了一半的帧丢了:输家被 drop,读了一半的状态跟着丢。
- Ticker 阻塞之后连着 tick 好几次:每次只加一个周期;从 tokio
interval搬过来,第一次 tick 晚一个周期。 - 通用定时器队列满了:不报错,忙转:
generic-queue-N容量不够时提前唤醒,变成忙等。 - 忘了 / 绑错 bind_interrupts!:E0277;重复绑定是
symbol EXTI15_10 is already defined。 - 外设被吃掉之后:E0382 / E0499 / E0597;
init called more than once!。 - the trait bound PA0: RxPin USART1 is not satisfied:引脚不能接这个外设,报错里列出可用的引脚。
- BufferedUart 第二次 write 卡住:0.6.0 丢唤醒,main 已修、未发版。
- adding a socket to a full SocketSet:
StackResources<N>要算上 DHCP、DNS。 - connect 一直不返回:对端不存在时只发 ARP;超时返回
ConnectionReset;drop 不发 FIN。 - Descriptor buffer full / control buffer too small:
Builder的几块缓冲区要算够,字符串描述符的检查差一个字节。 - packet-trace 加 log:[u8]: LowerHex is not satisfied:只有 defmt 能编,上游问题。
- there is no reactor running:在 embassy 任务里用 tokio 的类型。
按出在哪里分:
| 出在哪里 | 坑 |
|---|---|
| 时间驱动与 feature | 1 没有驱动、2 两个驱动、3 tick-hz、4 平台、5 trace |
| 任务与宏 | 6 池满、7 token、8 宏报错、9 任务大小 |
| 调度与阻塞 | 10 忙等、11 多个等待者、14 外来 waker、28 tokio |
| 同步原语 | 12 Noop 静态、13 中断里的锁、15 Signal、16 PubSub、17 select |
| 定时器 | 18 Ticker、19 通用队列 |
| HAL | 20 中断绑定、21 外设所有权、22 引脚、23 BufferedUart |
| 网络与 USB | 24 SocketSet、25 connect、26 USB 缓冲区、27 packet-trace |
flowchart TB
q{"碰到了什么"}
q -->|链接失败| lk{"哪个符号"}
lk -->|"_embassy_time_now"| p12["1 或 2"]
lk -->|"__embassy_trace_*"| p5["5 trace"]
lk -->|"EXTI15_10"| p20["20 中断绑定"]
q -->|编译失败| cf{"哪一句"}
cf -->|"TICK_HZ"| p3["3 tick-hz"]
cf -->|"No architecture"| p4["4 平台"]
cf -->|"task 宏"| p8["8 宏报错"]
cf -->|"cannot be shared"| p12b["12 Noop"]
cf -->|"E0277 Binding 或 Pin"| p2022["20 或 22"]
cf -->|"E0382 E0499 E0597"| p21["21 外设"]
cf -->|"LowerHex"| p27["27 packet-trace"]
q -->|运行期 panic| pn{"原文"}
pn -->|"Busy"| p6["6 池满"]
pn -->|"SpawnToken"| p7["7 token"]
pn -->|"BorrowMutError"| p13["13 中断里的锁"]
pn -->|"Found waker"| p14["14 外来 waker"]
pn -->|"full SocketSet"| p24["24 SocketSet"]
pn -->|"buffer full"| p26["26 USB"]
pn -->|"no reactor"| p28["28 tokio"]
q -->|卡住或丢数据| st{"哪种"}
st -->|"别的任务都停了"| p10["10 忙等"]
st -->|"CPU 不睡"| p1119["11 或 19"]
st -->|"有人收不到"| p1516["15 或 16"]
st -->|"帧丢一半"| p17["17 select"]
st -->|"连着 tick"| p18["18 Ticker"]
st -->|"write 不返回"| p23["23 BufferedUart"]
st -->|"connect 不返回"| p25["25 connect"]
💬 关联讨论
发起讨论加载中...