rust嵌入式开发之总结 (二)Embassy的不足

我们用rust+Embassy开发的新版产品已经投产了一个多月了,经历过近距离的强干扰、连绵的阴雨天失电等考验,初步证明了整个产品体系的稳定性。

经历过开发、测试以及这段时间的运行后,我也发现了Embassy的一些问题,之前的几篇文章都在说它的好处,所以集中说一下它的问题,以帮助大家能正确而全面的进行评估。

供应链难以维持

先概括一下我所认为的Embassy发力点:较为全面的对芯片的支持+async/await的支持。

Embassy支持了几个芯片系列,其它我没用所以无法评价,所以我只针对我使用的STM32来说。这里的较为全面,就STM32系列来说,应该说是非常保守了。

我们因为串口用的很多,所以选的是10串口的STM32F413VG,因为要用到DMA,所以只能用到7个串口,Embassy完全符合手册的说明,所以只要根据CubeMX配置结果来选串口以及对应的DMA通道就可以了,没有任何的问题。

也就是说,Embassy对STM32芯片的支持是全方面的,同时还提供了自己的HAL,所有芯片的操作接口是相同的,这是非常有意义的。

但其第一个问题也就来了:不支持GD32等对应STM32的国产芯片。这在国产替代的当下,显然是一个非常突出的严重问题。

我们在确定rust+Embassy+STM32这条技术路线的时候,当然对供应链做过调查,确认是足以满足我们的供应的,虽然F413目前全国库存只有100多片!!但我们的用量并不是很大,买上一批就够我们用上一段时间的了。

但是,架不住我们其它辅助器件的芯片断供啊!

我们现在不得不考虑全产品都要全面使用国产芯片的技术路线的巨大调整了:(

所以,Embassy的第一个问题就是如何规避供应问题,此外还要面对越来越高的国产替代要求。

函数动态调用消耗巨大

在c中动态调用一个函数非常简单:预先保存好对应的函数指针,需要时直接调用就好了。

rust当然和c一样,可以使用函数指针,但这个函数指针只能调用同步函数,无法执行异步操作。

这就比较麻烦了,我们的状态机、命令行、远程控制,甚至包括debug功能,都需要异步操作,如最简单的将信息打印到控制台,就是异步的,其它如等待、定时、IO操作等等,更都必须是异步的。

我最终的解决办法就是在初始化这些模块时,提供一个spawner,各模块将这个spawner保存起来,然后在回调的同步函数指针中用这个spawner来spaw一个异步任务。

这样的迂回自然带来了spawner保存的开销、异步任务调用的繁琐【需要4个函数的逐步调用才能真正启动c中简单的一个函数指针的执行】,同时还带来了代码书写的繁琐!

这些开销自然还可以忍受,但我在测试的时候,发现了一个巨大的bug:这些命令行、远程控制最多只能执行三四个,再多就会崩溃了!!

经过排查,发现这是由于Embassy启动异步任务的锅,Embassy自动生成的异步任务的调用代码是:

fn system_reboot_inner(mi: u32,purpose: DualPurpose,params: Option<BTreeMap<String, Value>>,
) -> ::embassy_executor::SpawnToken<impl Sized> {const POOL_SIZE: usize = 1;static POOL: ::embassy_executor::_export::TaskPoolRef = ::embassy_executor::_export::TaskPoolRef::new();unsafe {POOL.get::<_, POOL_SIZE>()._spawn_async_fn(move || __system_reboot_inner_task(mi, purpose, params))}
}

即一个任务分配一个任务池,静态的任务池,而spaw的任务是Sized的

由于时间太紧,我没有进一步的研究Embassy的异步任务机制,但根据这些代码和我所遇到的bug,我有理由相信:Embassy是将所有的异步任务的代码从flash加载到ram中静态保存,任务结束也并不释放!直接导致三四个动态任务执行后内存被消耗一空。

这个bug直接导致我们对于远程控制进行了剪裁,大量的功能从远程控制中取消,同时状态机也暂停使用,虽然在第一个版本中,这是可以接受的,但这无疑导致我在上篇文章中所说的我们选择rust嵌入式的理由大打折扣!

不支持park、block_on等std下的异步功能

Embassy实现了自己的executor,但实现的又不够完整!这主要就表现在park和block_on上。

不支持park,任务就无法一分为二,只能一根筋的自己跑完,简单的说就是无法自己启动一个新任务来执行某些操作。但有些时候,并不适合自己执行,而应该是启动一个子任务放到后台来做【类似python、go中的协程】。

那有些兄弟就会说,可以启动async啊!对,可是正如我上面所说,有时我们是在一个同步函数里,是没办法执行async的。

这时就需要block_on来帮我们在同步函数里执行async函数或闭包。

但是,Embassy的block_on是这个样子的:

pub fn block_on<F: Future>(mut fut: F) -> F::Output {// safety: we don't move the future after this line.let mut fut = unsafe { Pin::new_unchecked(&mut fut) };let raw_waker = RawWaker::new(ptr::null(), &VTABLE);let waker = unsafe { Waker::from_raw(raw_waker) };let mut cx = Context::from_waker(&waker);loop {if let Poll::Ready(res) = fut.as_mut().poll(&mut cx) {return res;}}
}

直接一个死循环反复的调future的poll!cpu直接干满100%,只能等中断才会有反馈,看门狗的喂狗都完蛋了!

结语

概要之,Embassy部分实现了rust的异步机制,提供了async/await,是一个巨大的进步,最典型的就是我之前所讲解的利用await来实现应用级的临界区,这对降低rust在嵌入式编程方面的门槛起到了巨大的作用。

但由于Embassy对rust异步机制支持的不完备,又严重制约了我们灵活的提供一些强大的功能:(

即,Embassy对无需动态执行任务的应用场景是非常良好的,但如果需要动态执行任务,那其显然是无法满足的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/860065.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

秋招突击——6/20——复习{(单调队列优化)——最大子序列和,背包问题——宠物小精灵收服问题}——新作{两两交换链表中的节点}

文章目录 引言复习单调队列优化——最大子序列和思路分析实现代码参考实现 背包问题——宠物小精灵的收服问题个人实现参考实现 新作两两交换链表中的节点个人实现参考实现 删除有序数组中的重复项个人实现知识补全迭代器的访问和控制vector删除特定的元素erasevector底层删除元…

深入探索B树:基本操作与应用解析

在计算机科学中&#xff0c;B树是一种自平衡的树形数据结构&#xff0c;广泛用于数据库和文件系统的索引结构。它能够提供高效率的数据检索、插入和删除操作&#xff0c;特别适合于磁盘I/O密集型的应用场景。本文将详细探讨B树的基本操作&#xff0c;包括B树的定义、特性、插入…

使用达梦DMHS平滑迁移Oracle数据到DM8

一、迁移前准备 1.环境描述 服务 IP 架构 Oracle 192.168.10.91/92 RAC、主库 Oracle 192.168.10.98 DG备库 达梦 192.168.10.192/192.168.10.193 主备 DMHS 192.168.10.193&#xff08;DM端&#xff09; 192.168.10.98&#xff08;Oracle端&#xff09; DTS …

PHP 数组排序详解与实例

在PHP编程中&#xff0c;数组是一种非常常见和重要的数据结构&#xff0c;而对数组进行排序则是处理和展示数据时必不可少的操作之一。本文将详细介绍PHP中数组排序的各种方法、函数和示例&#xff0c;帮助您掌握如何根据不同需求对数组进行排序。 1. PHP 中的数组排序函数 PH…

Consul入门笔记

简介 Consul&#xff0c;HashiCorp公司推出的开源工具&#xff0c;用于实现分布式系统的服务发现与配置。与其他分布式服务注册与发现的方案&#xff0c;Consul的方案更一站式&#xff0c;内置服务注册与发现框架、分布一致性协议实现、健康检查、K/V存储、多数据中心方案&…

面试-java并发与多线程的部分函数

1.sleep和wait的区别 基本的差别&#xff1a; Sleep是Thread的方法。Wait是object方法。Wait不传参&#xff0c;最终也是调用wait(native)的传参方法。 Sleep方法可以在任何地方使用。 Wait方法只能在synchronized方法或synchronized方法块中使用。 最主要的本质区别&#xf…

day 66 图论part03 101.孤岛的总面积 102.沉没孤岛 103.水流问题 104.建造最大岛屿

101.孤岛的总面积 本题使用dfs&#xff0c;bfs&#xff0c;并查集都是可以的。 本题要求找到不靠边的陆地面积&#xff0c;那么我们只要从周边找到陆地然后 通过 dfs或者bfs 将周边靠陆地且相邻的陆地都变成海洋&#xff0c;然后再去重新遍历地图 统计此时还剩下的陆地就可以…

【NOI】C++程序结构入门之嵌套循环一

文章目录 前言一、嵌套循环1.概念2.语法2.1 for循环嵌套for2.2 while循环嵌套for2.3 while循环嵌套while2.4for循环嵌套while2.5 注意2.5.1内层循环之前2.5.2内层循环之后 3.按位检查 二、例题讲解问题&#xff1a;1448. 随机体能测试问题&#xff1a;1469. 数的统计问题&#…

vue中图谱关系插件relation-graph

vue中图谱关系插件relation-graph 一、效果图二、安装下载&#xff08;vue2.0版本的&#xff09;三、直接上代码 一、效果图 二、安装下载&#xff08;vue2.0版本的&#xff09; npm install --save relation-graph var foo bar;三、直接上代码 <template><div cla…

基于 imx6ull 平台使用opencv4.7.0处理图片

本章节是针对opencv-4.7.0移植到 linux imx6ull系统&#xff0c;运行在Linux上&#xff0c;详细的移植流程请参考前面针对imx6ull平台移植opencv4.7.0&#xff0c;主要是针对应用开发&#xff0c;主要是对图片显示、旋转、缩放、显示字幕等应用场景开发。 二、环境要求 2.1 硬…

el-input 格式化输入值

1. 只允许输入数字&#xff0c;并保留两位小数<el-inputclass"config-input"type"number"v-model"v.minHeight"placeholder"":min"0"input"v.minHeight Number(Number(v.minHeight).toFixed(2))"/ 2. 只允许输…

半导体厂车间内如何实施等级保护

等级保护,全称为信息安全等级保护,是指根据信息系统在国家安全、经济建设、社会生活中的重要程度,以及信息系统一旦遭受破坏可能带来的影响和危害程度,对信息系统进行分等级保护的一种制度。在中国,等级保护通常分为五个等级,每个等级都有相应的保护要求和标准。 对于生…

【从0实现React18】 (五) 初探react mount流程 完成核心递归流程

更新流程的目的&#xff1a; 生成wip fiberNode树标记副作用flags 更新流程的步骤&#xff1a; 递&#xff1a;beginWork归&#xff1a;completeWork 在 上一节 &#xff0c;我们探讨了 React 应用在首次渲染或后续更新时的整体更新流程。在 Reconciler 工作流程中&#xff…

LLC开关电源开发:LLC设计参考文档(模态分析)

电源简析和全桥LLC模型分析 1.1模拟电源、开关电源和数字电源简介 1.1.1 模拟电源 模拟电源&#xff1a;即变压器电源&#xff0c;通过铁芯、线圈来实现&#xff0c;线圈的匝数决定了两端的电压比&#xff0c;铁芯的作用是传递变化磁场&#xff0c;&#xff08;我国&#xff09…

C语言——关键字 static volatile const extern 用法

static 不污染内存空间 用法&#xff1a; static void helperFunction() {// 实现细节 } /*在函数声明前加上"static"关键字可以将函数的作用域限制在当前源文件中。静态函数只能在当前源文件中调用&#xff0c;不能被其他源文件调用。使用静态函数有助于隐藏实现细…

摒弃反模式:使用Kotlin委托优化Android BaseActivity

摒弃反模式&#xff1a;使用Kotlin委托优化Android BaseActivity 在Android开发中&#xff0c;许多开发者习惯于创建名为“BaseActivity”或“BaseFragment”的基类&#xff0c;以便在所有Activity或Fragment中共享一些通用行为。这种方法乍一看似乎是个好主意&#xff0c;但实…

用Python制作幸运大转盘,抽奖转盘对比-tkinter(Python的内置GUI库)和pygame(一个更强大的游戏和多媒体应用库)——小白也能轻松看懂

一、要制作一个幸运大转盘&#xff08;抽奖转盘&#xff09;的Python程序&#xff0c;你可以使用图形库如tkinter&#xff08;Python的内置GUI库&#xff09;或者pygame&#xff08;一个更强大的游戏和多媒体应用库&#xff09;。由于tkinter更为简单和直接&#xff0c;以下是一…

零基础女生如何入门人工智能,从哪里下手?学习时间大概要多久?

作为一个理工科早期毕业生&#xff0c;出于近乎本能的敏感&#xff0c;格外关注全网热议的ChatGPT。 本来国内就业环境就不好&#xff0c;各行各业内卷越来越严重&#xff0c;加上人工智能的异军突起&#xff0c;各行各业势必将迎来科技进步跨时代的巨大冲击&#xff0c;在此情…

000005 - HDFS 读写流程

HDFS 读写流程 1 HDFS 写数据流程1.1 HDFS 写数据流程图1.2 HDFS 写数据之网络拓扑 - 节点距离计算1.3 机架感知&#xff08;副本存储节点选择&#xff09; 2 HDFS 读数据流程2.1 HDFS 读数据流程图 3 HDFS 如何做到机架感知 1 HDFS 写数据流程 1.1 HDFS 写数据流程图 &#x…

【代码随想录刷题】day02——977.有序数组的平方 ,209.长度最小的子数组 ,59.螺旋矩阵II

977.有序数组的平方 方法一&#xff1a;暴力法 class Solution { public:vector<int> sortedSquares(vector<int>& nums) {// 暴力法for(int i 0; i < nums.size(); i){nums[i] * nums[i];}sort(nums.begin(), nums.end());return nums;} };方法二&#…