Day5: platformDriver-1
Platform Driver (1)
Linux kernel中大部分设备可以归结为平台设备,因此大部分的驱动是平台驱动(patform driver)
什么是平台设备
平台设备是linux的设备模型中一类设备的抽象。 内核中的描述:
Platform devices are devices that typically appear as autonomous entities in the system. This includes legacy port-based devices and host bridges to peripheral buses, and most controllers integrated into system-on-chip platforms. What they usually have in common is direct addressing from a CPU bus. Rarely, a platform_device will be connected through a segment of some other kind of bus; but its registers will still be directly addressable.
一句话来描述就是: CPU能够直接寻址的SOC上的外设

图1:Platform设备
图1中的uart控制器,I2C控制器,GPIO控制器等,都是平台设备。
可以说,paltform设备对Linux驱动工程师是非常重要的,因为我们编写的大多数设备驱动,都是为了驱动plaftom设备。
Platform设备在内核中的实现主要包括三个部分:
- Platform Bus,基于底层bus模块,抽象出一个虚拟的Platform bus,用于挂载Platform设备;
- Platform Device,基于底层device模块,抽象出Platform Device,用于表示Platform设备;
- Platform Driver,基于底层device_driver模块,抽象出Platform Driver,用于驱动Platform设备
对于图1中的I2C控制器挂载在platform Bus上,因此我们在linux kernel中常说的I2C driver,都是指I2C controller driver,都是以platform driver的形式存在,当然,对应的控制器是platform device。
与此同时,kernel抽象出I2C bus(/sys/bus/i2c),用于挂载和I2C controller通过I2C总线连接的各个I2C slave device。
串口驱动开发
驱动开发框架
得益于设备模型,Linux kernel平台驱动的开发有了一套非常固定的框架
1)模块的入口和出口
用于注册/注销platform driver,这一部分的代码基本固定,包括函数和变量的命名方式也可固定,如下:
/* 驱动模块加载 */static int __init xxxdriver_init(void){return platform_driver_register(&xxx_driver);}/* 驱动模块卸载 */static void __exit xxxdriver_exit(void){platform_driver_unregister(&xxx_driver);}module_init(xxxdriver_init);module_exit(xxxdriver_exit);MODULE_LICENSE("GPL V2");MODULE_AUTHOR("QianRuShi-ABC");
2)platform driver
基本的platform driver包含三要素:struct platform_driver变量、probe/remove函数、用于和device tree匹配的match table,如下:
/** platform 平台驱动结构体*/
static struct platform_driver xxx_driver = {.driver = {.name = "xxx",.of_match_table = xxx_of_match,},.probe = xxx_probe,.remove = xxx_remove,
};/** platform 驱动的 probe 函数* 驱动与设备匹配成功以后此函数就会执行*/static int xxx_probe(struct platform_device *dev){match = of_match_device(xxx_of_match, &pdev->dev);if (!match) {dev_err(&pdev->dev, "Error: No device match found\n");return -ENODEV;}return 0;}static int xxx_remove(struct platform_device *dev){....../* 函数具体内容 */return 0;}/* 匹配列表 */static const struct of_device_id xxx_of_match[] = {{ .compatible = "xxx-xxx" },{ /* Sentinel */ }};
注意,xxx_of_match中的.compatible需要和DTS文件中的compatible对应,一般格式是“厂商名称,芯片系列-模块名”,例如“actions,s900-serial”
##串口驱动
串口设备(serial or uart,后面不再区分)是TTY设备的一种,Linux kernel为了方便串口驱动的开发,在TTY framework的基础上,封装了一层串口框架(serial framework)。该框架尽可能的屏蔽了TTY有关的技术细节(比较难懂),驱动工程师在编写串口驱动的时候,只需要把精力放在串口以及串口控制器本身即可。
Linux kernel serial framework位于“drivers/tty/serial”目录中,其软件架构(如下面图2所示)比较简单:

图2: serialFramework
Serial core是Serial framework的核心实现,对上封装、屏蔽TTY的技术细节,对下为具体的串口驱动提供简单、统一的编程API。
Serial drivers就是具体的串口驱动。
Serial Core
serial core主要实现如下三类功能
1)将串口设备有关的物理对象(及其操作方法)封装成一个一个的数据结构,以达到用软件语言描述硬件的目的。
2)向底层driver提供串口驱动的编程接口。
3)基于TTY framework所提供的TTY driver的编写规则,将底层driver看到的serial driver,转换为TTY driver,并将所有的serial操作,转换为对应的tty操作。
关键数据结构
struct uart_port
struct uart_state
struct uart_ops
struct uart_driver
API:
int uart_register_driver(struct uart_driver *uart);
void uart_unregister_driver(struct uart_driver *uart);int uart_add_one_port(struct uart_driver *reg, struct uart_port *port);
int uart_remove_one_port(struct uart_driver *reg, struct uart_port *port);
int uart_match_port(struct uart_port *port1, struct uart_port *port2);int uart_suspend_port(struct uart_driver *reg, struct uart_port *port);
int uart_resume_port(struct uart_driver *reg, struct uart_port *port);static inline int uart_tx_stopped(struct uart_port *port)extern void uart_insert_char(struct uart_port *port, unsigned int status,unsigned int overrun, unsigned int ch, unsigned int flag);
串口驱动的移植步骤
- 定义并注册uart driver
- 注册uart port
- 定义并实现uart ops
定义并注册uart driver
static struct uart_driver imx_reg = {.owner = THIS_MODULE,.driver_name = DRIVER_NAME,.dev_name = DEV_NAME,.major = SERIAL_IMX_MAJOR,.minor = MINOR_START,.nr = ARRAY_SIZE(imx_ports),.cons = IMX_CONSOLE,
};
注册uart port
platform device代表uart控制器,是实体抽象。对应的,uart port代表“串口”. 因此,我们需要在platform device probe的时候(platform driver的probe接口),动态分配并注册一个uart port(struct uart_port)。在后续的串口操作中,都是以uart port指针为对象. 见下一章节代码中i.mx6的驱动代码。
定义并实现uart ops
struct uart_ops结构包含了各式各样的uart端口的操作函数,需要在添加uart port的时候提供.见下一章节代码中i.mx6的驱动代码
完整代码
对应驱动开发框架中,1)模块的入口和出口
static int __init imx_serial_init(void)
{int ret = uart_register_driver(&imx_reg);if (ret)return ret;ret = platform_driver_register(&serial_imx_driver);if (ret != 0)uart_unregister_driver(&imx_reg);return ret;
}static void __exit imx_serial_exit(void)
{platform_driver_unregister(&serial_imx_driver);uart_unregister_driver(&imx_reg);
}module_init(imx_serial_init);
module_exit(imx_serial_exit);MODULE_AUTHOR("Sascha Hauer");
MODULE_DESCRIPTION("IMX generic serial port driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:imx-uart");
对应驱动开发框架中,2)platform driver
基本的platform driver包含三要素:struct platform_driver变量、probe/remove函数、用于和device tree匹配的match table
- struct platform_driver变量
static struct platform_driver serial_imx_driver = {.probe = serial_imx_probe,.remove = serial_imx_remove,.suspend = serial_imx_suspend,.resume = serial_imx_resume,.id_table = imx_uart_devtype,.driver = {.name = "imx-uart",.of_match_table = imx_uart_dt_ids,},
};
- robe/remove函数
static int serial_imx_probe(struct platform_device *pdev) {struct imx_port *sport;void __iomem *base;int ret = 0;struct resource *res;int txirq, rxirq, rtsirq;sport = devm_kzalloc(&pdev->dev, sizeof(*sport), GFP_KERNEL);if (!sport)return -ENOMEM;ret = serial_imx_probe_dt(sport, pdev);if (ret > 0)serial_imx_probe_pdata(sport, pdev);else if (ret < 0)return ret;res = platform_get_resource(pdev, IORESOURCE_MEM, 0); base = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(base))return PTR_ERR(base);rxirq = platform_get_irq(pdev, 0); txirq = platform_get_irq(pdev, 1); rtsirq = platform_get_irq(pdev, 2);sport->port.dev = &pdev->dev; sport->port.mapbase = res->start; sport->port.membase = base; sport->port.type = PORT_IMX, sport->port.iotype = UPIO_MEM; sport->port.irq = rxirq; sport->port.fifosize = 32; sport->port.ops = &imx_pops; sport->port.rs485_config = imx_rs485_config; sport->port.rs485.flags =SER_RS485_RTS_ON_SEND | SER_RS485_RX_DURING_TX; sport->port.flags = UPF_BOOT_AUTOCONF; init_timer(&sport->timer); sport->timer.function = imx_timeout; sport->timer.data = (unsigned long)sport;sport->clk_ipg = devm_clk_get(&pdev->dev, "ipg"); if (IS_ERR(sport->clk_ipg)) {ret = PTR_ERR(sport->clk_ipg);dev_err(&pdev->dev, "failed to get ipg clk: %d\n", ret);return ret; }sport->clk_per = devm_clk_get(&pdev->dev, "per"); if (IS_ERR(sport->clk_per)) {ret = PTR_ERR(sport->clk_per);dev_err(&pdev->dev, "failed to get per clk: %d\n", ret);return ret; }sport->port.uartclk = clk_get_rate(sport->clk_per); if (sport->port.uartclk > IMX_MODULE_MAX_CLK_RATE) {ret = clk_set_rate(sport->clk_per, IMX_MODULE_MAX_CLK_RATE);if (ret < 0) {dev_err(&pdev->dev, "clk_set_rate() failed\n");return ret;} } sport->port.uartclk = clk_get_rate(sport->clk_per);/** Allocate the IRQ(s) i.MX1 has three interrupts whereas later* chips only have one interrupt.*/ if (txirq > 0) {ret = devm_request_irq(&pdev->dev, rxirq, imx_rxint, 0,dev_name(&pdev->dev), sport);if (ret)return ret;ret = devm_request_irq(&pdev->dev, txirq, imx_txint, 0,dev_name(&pdev->dev), sport);if (ret)return ret; } else {ret = devm_request_irq(&pdev->dev, rxirq, imx_int, 0,dev_name(&pdev->dev), sport);if (ret)return ret; } imx_ports[sport->port.line] = sport; platform_set_drvdata(pdev, sport); return uart_add_one_port(&imx_reg, &sport->port);
}
static int serial_imx_remove(struct platform_device *pdev)
{struct imx_port *sport = platform_get_drvdata(pdev);return uart_remove_one_port(&imx_reg, &sport->port);
}
- 用于和device tree匹配的match table
static const struct of_device_id imx_uart_dt_ids[] = {{ .compatible = "fsl,imx6q-uart", .data = &imx_uart_devdata[IMX6Q_UART], },{ .compatible = "fsl,imx1-uart", .data = &imx_uart_devdata[IMX1_UART], },{ .compatible = "fsl,imx21-uart", .data = &imx_uart_devdata[IMX21_UART], },{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, imx_uart_dt_ids);
对应串口驱动的移植步骤中,定义并注册uart driver
在驱动init函数中注册了uart driver
int ret = uart_register_driver(&imx_reg);
在linux serial framework中,uart driver是一个平行于platform driver的概念,用于驱动“虚拟”的“串口”设备。
#define DRIVER_NAME "IMX-uart"static struct uart_driver imx_reg = {.owner = THIS_MODULE,.driver_name = DRIVER_NAME,.dev_name = DEV_NAME,.major = SERIAL_IMX_MAJOR,.minor = MINOR_START,.nr = ARRAY_SIZE(imx_ports),.cons = IMX_CONSOLE,
};
对应串口驱动的移植步骤中,注册uart port
假如一个soc中有5个串口控制器(也可称作uart控制器,后面我们不再区分),每个uart控制器都可引出一个串口(uart port)。那么:
每个uart控制器,都是一个platform device,由dts文件的一个node描述。而这5个platform device,可由同一个driver驱动,即platform driver。
相对于uart控制器实实在在的存在,我们更为熟悉的串口(uart port),则是虚拟的设备,它们由“struct uart_port”描述(后面会介绍),并在platform driver的probe接口中,注册到kernel。它们可由同一个driver驱动,即这里所说的uart driver。
struct imx_port {struct uart_port port;struct timer_list timer;unsigned int old_status;unsigned int have_rtscts:1;unsigned int dte_mode:1;unsigned int irda_inv_rx:1;unsigned int irda_inv_tx:1;unsigned short trcv_delay; /* transceiver delay */struct clk *clk_ipg;struct clk *clk_per;const struct imx_uart_data *devdata;/* DMA fields */unsigned int dma_is_inited:1;unsigned int dma_is_enabled:1;unsigned int dma_is_rxing:1;unsigned int dma_is_txing:1;struct dma_chan *dma_chan_rx, *dma_chan_tx;struct scatterlist tx_sgl[2];struct imx_dma_rxbuf rx_buf;unsigned int tx_bytes;unsigned int dma_tx_nents;struct delayed_work tsk_dma_tx;wait_queue_head_t dma_wait;unsigned int saved_reg[10];
#define DMA_TX_IS_WORKING 1unsigned long flags;
};
在platform driver的probe函数中会动态分配并注册一个uart port(struct uart_port)然后初始化并注册其中的port变量。初始化完之后,直接调用uart_add_one_port接口,将该port添加到kernel serial core
再返回上面的static int serial_imx_probe(struct platform_device *pdev)展开看到
//分配struct xxx_port类型的指针
struct imx_port *sport;
sport = devm_kzalloc(&pdev->dev, sizeof(*sport), GFP_KERNEL);
//获取中断号,该串口对应的中断号, 一般是从DTS中解析得到的;rxirq = platform_get_irq(pdev, 0);txirq = platform_get_irq(pdev, 1);rtsirq = platform_get_irq(pdev, 2);
//初始化并注册其中的port变量sport->port.dev = &pdev->dev;sport->port.mapbase = res->start;sport->port.membase = base;sport->port.type = PORT_IMX,sport->port.iotype = UPIO_MEM;sport->port.irq = rxirq;sport->port.fifosize = 32;sport->port.ops = &imx_pops;sport->port.rs485_config = imx_rs485_config;sport->port.rs485.flags =SER_RS485_RTS_ON_SEND | SER_RS485_RX_DURING_TX;sport->port.flags = UPF_BOOT_AUTOCONF;init_timer(&sport->timer);sport->timer.function = imx_timeout;sport->timer.data = (unsigned long)sport;
在proble函数的最后,调用uart_add_one_port接口,将该port添加到kernel serial core
return uart_add_one_port(&imx_reg, &sport->port);
对应串口驱动的移植步骤中,定义并实现uart ops
上面platform driver的probe函数serial_imx_probe,展开中看到
sport->port.ops = &imx_pops;
struct uart_ops结构包含了各式各样的uart端口的操作函数,需要在添加uart port的时候提供。
static struct uart_ops imx_pops = {.tx_empty = imx_tx_empty,.set_mctrl = imx_set_mctrl,.get_mctrl = imx_get_mctrl,.stop_tx = imx_stop_tx,.start_tx = imx_start_tx,.stop_rx = imx_stop_rx,.enable_ms = imx_enable_ms,.break_ctl = imx_break_ctl,.startup = imx_startup,.shutdown = imx_shutdown,.flush_buffer = imx_flush_buffer,.set_termios = imx_set_termios,.type = imx_type,.config_port = imx_config_port,.verify_port = imx_verify_port,
#if defined(CONFIG_CONSOLE_POLL).poll_init = imx_poll_init,.poll_get_char = imx_poll_get_char,.poll_put_char = imx_poll_put_char,
#endif
};
个人公众号交流

#参考
http://www.wowotech.net/x_project/serial_driver_porting_1.html
http://www.wowotech.net/x_project/serial_driver_porting_2.html
http://www.wowotech.net/x_project/serial_driver_porting_3.html
http://www.wowotech.net/x_project/serial_driver_porting_4.html
http://www.wowotech.net/comm/serial_overview.html
相关文章:
Day5: platformDriver-1
Platform Driver (1) Linux kernel中大部分设备可以归结为平台设备,因此大部分的驱动是平台驱动(patform driver) 什么是平台设备 平台设备是linux的设备模型中一类设备的抽象。 内核中的描述: Platform devices are devices t…...
开发手册——一、编程规约_7.控制语句
这篇文章主要梳理了在java的实际开发过程中的编程规范问题。本篇文章主要借鉴于《阿里巴巴java开发手册终极版》 下面我们一起来看一下吧。 1. 【强制】在一个 switch 块内,每个 case 要么通过 break / return 等来终止,要么注释说明程序将继续执行到哪…...
python每日学9 : windows上配置gitee的远程仓库,git的初步使用
在开发中,如果遇到复杂的项目,使用版本控制是非常有必要的,如果涉及到多端开发,那么还需要使用远程仓库。本文作个简单记录,记录下git初步使用。 1 下载与安装 git还有几个ui版本,但是开始使用的话&#…...
精确率与召回率,ROC曲线与PR曲线
精确率与召回率,ROC曲线与PR曲线 在机器学习的算法评估中,尤其是分类算法评估中,我们经常听到精确率(precision)与召回率(recall),ROC曲线与PR曲线这些概念,那这些概念到底有什么用处呢? 首先,…...
现代操作系统——Linux架构与学习
小白的疑惑 在我决定从事嵌入式(应用层)方面的工作时,我查询了大量资料该如何学习,几乎所有观点不约而同的都指向了学习好Linux,大部分工作都是在Linux环境下来进行工作的。于是我雄心勃勃的去下载Linux,可…...
中文代码82
PK 嘚釦 docProps/PK 嘚釦羸 r docProps/app.xml潙蚽?勶曻Q顗濔S? 錞礖剅D柍珘m?鳞?ぷ辷f硌?2?upc厭Y樐8 rU y搪m眾&a?珪?紓 玺鶋瑣襚? ?i嘲rN?布倖儇?攊橌??嚗猝)芻矂2吟腊K湞?CK臶>鸘\?ΔF滋齢q旮T?桀?;偉 A軥v蕯朾偤佷3?е…...
顺序表(一篇带你掌握顺序表)
目录 一、顺序表是什么 1.1 概念 1.2 分类 1.3 结构 二、顺序表的基本操作 2.1 前绪准备 2.2 初始化 2.3 扩容 2.5 尾插 2.6 打印 2.7 尾删 2.8 头插 2.9 头删 2.10 在pos位置插入 2.11 删除pos位置的数据 2.12 查找 三、完整代码 3.1 Test.c文件 3.2 SeqList.h…...
【SpringCloud】SpringCloud教程之Feign实战
目录前言SpringCloud Feign远程服务调用一.需求二.两个服务的yml配置和访问路径三.使用RestTemplate远程调用(order服务内编写)四.构建Feign(order服务内配置)五.自定义Feign配置(order服务内配置)六.Feign配置日志(oder服务内配置)七.Feign调优(order服务内配置)八.抽离Feign前…...
嵌入式linux必备内存泄露检测神器
Valgrind介绍 Valgrind是一个可移植的动态二进制分析工具集,主要用于发现程序中的内存泄漏、不合法内存访问、使用未初始化的内存、不正确的内存释放以及性能问题等,可在Linux和Mac OS X等平台上使用。 Valgrind由多个工具组成,其中最常用的…...
设计模式之行为型模式
四、行为型模式 行为型模式用于描述程序在运行时复杂的流程控制,即描述多个类或对象之间怎样相互协作共同完成单个对象都无法单独完成的任务,它涉及算法与对象间职责的分配。 行为型模式分为类行为模式和对象行为模式,前者采用继承机制来在…...
解密 三岁的三岁到底为什么叫做三岁?
机缘 那一年,一次奇奇怪怪的挫折与一次奇奇怪怪的成长。 在学习Python的路上总觉得少了点什么,是心情?是机遇?还是力量? 都不是又都是! 缺少一个实践和记忆的平台 记性不好是硬伤 前一天学的下一秒就忘记了…...
id选择器
id选择器可以为特定的id的标签进行css美化 使用方法: 标签内设好 id值, CSS的id选择器以“#id名”来调用 注意 所有标签都有id值id属性值类似于身份证号码,在一个页面中是唯一的值,不可重复一个标签上只能有一个id属性值一个id属性…...
《科技之巅3》读书笔记
文章目录书籍信息人工智能,“吃一堑长一智”的机器人机交互,为解决“交流障碍”问题而生硬件与算法,好马还需好鞍模式创新,赋予技术新的定义云与数据共享,灵活应对信息的爆发式增长“机器人”,从电影和小说…...
18.用于大型程序的工具
文章目录用于大型程序的工具18.1异常处理18.1.1抛出异常栈展开栈展开过程中对象被自动销毁析构函数与异常异常对象18.1.2捕获异常查找匹配的处理代码重新抛出捕获所有异常的处理代码18.1.3函数try语句块与构造函数18.1.4noexcept异常说明违反异常说明异常说明的实参noexcept运算…...
mysql一主键uuid和自增的选择
文章目录 1.自增ID的优缺点1.1 优点1.2 缺点1.3 不适合以自增ID主键作为主键的情况2.UUID作为主键2.1 介绍2.2 优点2.3 缺点3.有序UUID作为主键3.1 介绍3.2 演示使用3.2.1 前提知识3.2.1.1 数据类型 - binary3.2.1.2 函数 - hex()3.2.1.3 函数 - unhex()3.2.2 数据库层3.2.3 JA…...
【EDA工具使用】——VCS和Verdi的联合仿真的简单使用
目录 1.芯片开发所需的工具环境 2.编译仿真工具 3.三步式混合编译仿真(最常用)编辑 4.两步式混合编译仿真编辑 5.VCS的使用 6.verdi的使用 1.产生fsdb文件的两种方法编辑 1.芯片开发所需的工具环境 2.编译仿真工具 3.三步式混合编译仿真…...
【Java学习笔记】4.Java 对象和类
前言 本章介绍Java的对象和类。 Java 对象和类 Java作为一种面向对象语言。支持以下基本概念: 多态继承封装抽象类对象实例方法重载 本节我们重点研究对象和类的概念。 对象:对象是类的一个实例(对象不是找个女朋友)&#x…...
39. 实战:基于api接口实现视频解析播放(32接口,窗口化操作,可导出exe,附源码)
目录 前言 目的 思路 代码实现 需要导入的模块 1. 导入解析网站列表,实现解析过程 2. 设计UI界面 3. 设置窗口居中和循环执行 4. 注意事项 完整源码 运行效果 总结 前言 本节将类似34. 实战:基于某api实现歌曲检索与下载(附完整…...
基于灵动 MM32 微控制器的便携式血氧仪方案
基于灵动 MM32 微控制器的便携式血氧仪: - Cortex-M0() 最高主频 72MHz 可实现血氧饱和度信号采集、算法操作和 LED 显示操作 - 高性能的 1Msps 12b ADC 能对光电采样结果进行大数据量的暂存和处理,提高采样的效率并有助于对结果做高精度的计算 - 100…...
2022秋-2023-中科大-数字图像分析-期末考试试卷回忆版
今天晚上刚考完,心累,在这里继续授人以渔(仅供参考,切勿对着复习不看ppt,ppt一定要过两遍)。 注意:往年的经验贴,到此为止,全部作废,一个没考。千万不要只对着复习,SIFT没考&#x…...
stm32G473的flash模式是单bank还是双bank?
今天突然有人stm32G473的flash模式是单bank还是双bank?由于时间太久,我真忘记了。搜搜发现,还真有人和我一样。见下面的链接:https://shequ.stmicroelectronics.cn/forum.php?modviewthread&tid644563 根据STM32G4系列参考手…...
阿里云ACP云计算备考笔记 (5)——弹性伸缩
目录 第一章 概述 第二章 弹性伸缩简介 1、弹性伸缩 2、垂直伸缩 3、优势 4、应用场景 ① 无规律的业务量波动 ② 有规律的业务量波动 ③ 无明显业务量波动 ④ 混合型业务 ⑤ 消息通知 ⑥ 生命周期挂钩 ⑦ 自定义方式 ⑧ 滚的升级 5、使用限制 第三章 主要定义 …...
3.3.1_1 检错编码(奇偶校验码)
从这节课开始,我们会探讨数据链路层的差错控制功能,差错控制功能的主要目标是要发现并且解决一个帧内部的位错误,我们需要使用特殊的编码技术去发现帧内部的位错误,当我们发现位错误之后,通常来说有两种解决方案。第一…...
屋顶变身“发电站” ,中天合创屋面分布式光伏发电项目顺利并网!
5月28日,中天合创屋面分布式光伏发电项目顺利并网发电,该项目位于内蒙古自治区鄂尔多斯市乌审旗,项目利用中天合创聚乙烯、聚丙烯仓库屋面作为场地建设光伏电站,总装机容量为9.96MWp。 项目投运后,每年可节约标煤3670…...
涂鸦T5AI手搓语音、emoji、otto机器人从入门到实战
“🤖手搓TuyaAI语音指令 😍秒变表情包大师,让萌系Otto机器人🔥玩出智能新花样!开整!” 🤖 Otto机器人 → 直接点明主体 手搓TuyaAI语音 → 强调 自主编程/自定义 语音控制(TuyaAI…...
均衡后的SNRSINR
本文主要摘自参考文献中的前两篇,相关文献中经常会出现MIMO检测后的SINR不过一直没有找到相关数学推到过程,其中文献[1]中给出了相关原理在此仅做记录。 1. 系统模型 复信道模型 n t n_t nt 根发送天线, n r n_r nr 根接收天线的 MIMO 系…...
大语言模型(LLM)中的KV缓存压缩与动态稀疏注意力机制设计
随着大语言模型(LLM)参数规模的增长,推理阶段的内存占用和计算复杂度成为核心挑战。传统注意力机制的计算复杂度随序列长度呈二次方增长,而KV缓存的内存消耗可能高达数十GB(例如Llama2-7B处理100K token时需50GB内存&a…...
在鸿蒙HarmonyOS 5中使用DevEco Studio实现企业微信功能
1. 开发环境准备 安装DevEco Studio 3.1: 从华为开发者官网下载最新版DevEco Studio安装HarmonyOS 5.0 SDK 项目配置: // module.json5 {"module": {"requestPermissions": [{"name": "ohos.permis…...
day36-多路IO复用
一、基本概念 (服务器多客户端模型) 定义:单线程或单进程同时监测若干个文件描述符是否可以执行IO操作的能力 作用:应用程序通常需要处理来自多条事件流中的事件,比如我现在用的电脑,需要同时处理键盘鼠标…...
苹果AI眼镜:从“工具”到“社交姿态”的范式革命——重新定义AI交互入口的未来机会
在2025年的AI硬件浪潮中,苹果AI眼镜(Apple Glasses)正在引发一场关于“人机交互形态”的深度思考。它并非简单地替代AirPods或Apple Watch,而是开辟了一个全新的、日常可接受的AI入口。其核心价值不在于功能的堆叠,而在于如何通过形态设计打破社交壁垒,成为用户“全天佩戴…...
