RK3568驱动指南|第十六篇 SPI-第188章 mcp2515驱动编写:复位函数

瑞芯微RK3568芯片是一款定位中高端的通用型SOC,采用22nm制程工艺,搭载一颗四核Cortex-A55处理器和Mali G52 2EE 图形处理器。RK3568 支持4K 解码和 1080P 编码,支持SATA/PCIE/USB3.0 外围接口。RK3568内置独立NPU,可用于轻量级人工智能应用。RK3568 支持安卓 11 和 linux 系统,主要面向物联网网关、NVR 存储、工控平板、工业检测、工控盒、卡拉 OK、云终端、车载中控等行业。


【公众号】迅为电子

【粉丝群】258811263(加群获取驱动文档+例程)

【视频观看】嵌入式学习之Linux驱动(第十六篇 SPI_全新升级)_基于RK3568

【购买链接】迅为RK3568开发板瑞芯微Linux安卓鸿蒙ARM核心板人工智能AI主板


  1. 第188章 mcp2515驱动编写:复位函数

在上一章中填充了mcp2515字符设备注册相关的内容,有了mcp2515对应的设备节点,而实际上仍旧属于编写通用SPI外设驱动的范畴,如果要编写其他外设的SPI驱动程序,同样要完成上一章编写的驱动内容,而从本章节开始才真正进入到mcp2515特性相关驱动的编写,在本章节将填充mcp2515的复位函数。

188.1 理论分析

MCP2515具有五种模式,分别为配置模式、正常模式、休眠模式、仅监听模式和环回模式,只有在配置模式下,才能对关键寄存器进行初始化和配置,当MCP2515上电或者复位时,器件会自动进入配置模式,而MCP2515提供了一系列的SPI指令,SPI指令表如下图所示:

通过向MCP2515发送上述SPI指令就能实现复位、读、写等操作,复位操作对应的指令格式为11000000,在Linux驱动中可以使用spi_write函数来实现向SPI从设备发送数据,spi_write函数定义在include/linux/spi/spi.h文件中,具体内容如下所示:

static inline int
spi_write(struct spi_device *spi, const void *buf, size_t len)
{struct spi_transfer	t = {.tx_buf		= buf,.len		= len,};return spi_sync_transfer(spi, &t, 1);
}

该函数首先会对要传输的数据以及传输的数据大小进行封装,然后调用spi_sync_transfer函数进行输入传输,spi_write函数传入的第一个参数为spi_device类型的结构体变量,struct spi_device是Linux内核中用于描述SPI从设备的结构体。它包含了与 SPI 设备相关的各种信息和配置选项,该结构体的具体内容如下所示:

struct spi_device {struct device dev; // 通用设备模型的设备结构体struct spi_controller *controller; // 指向控制器的指针struct spi_controller *master; // 兼容层,指向控制器的指针(与controller相同)u32 max_speed_hz; // 设备支持的最大速度(以赫兹为单位)u8 chip_select; // 片选编号u8 bits_per_word; // 每个字的位数u16 mode; // SPI 模式配置(包括时钟相位和极性等)int irq; // 中断号void *controller_state; // 控制器状态的私有数据void *controller_data; // 控制器数据的私有数据char modalias[SPI_NAME_SIZE]; // 设备别名const char *driver_override; // 驱动程序覆盖int cs_gpio; // 片选 GPIO 引脚struct spi_statistics statistics; // 统计数据/* mode flags */#define SPI_CPHA 0x01 // 时钟相位#define SPI_CPOL 0x02 // 时钟极性#define SPI_MODE_0 (0|0) // 模式0#define SPI_MODE_1 (0|SPI_CPHA) // 模式1#define SPI_MODE_2 (SPI_CPOL|0) // 模式2#define SPI_MODE_3 (SPI_CPOL|SPI_CPHA) // 模式3#define SPI_CS_HIGH 0x04 // 片选高电平有效#define SPI_LSB_FIRST 0x08 // 最低有效位先传输#define SPI_3WIRE 0x10 // 三线模式#define SPI_LOOP 0x20 // 环回模式#define SPI_NO_CS 0x40 // 无片选信号#define SPI_READY 0x80 // 从设备拉低以暂停#define SPI_TX_DUAL 0x100 // 双线发送#define SPI_TX_QUAD 0x200 // 四线发送#define SPI_RX_DUAL 0x400 // 双线接收#define SPI_RX_QUAD 0x800 // 四线接收#define SPI_CS_WORD 0x1000 // 每个字后切换片选
};

所以在调用spi_write函数之前需要先定义一个struct spi_device类型的用于描述SPI设备的结构体,然后来编写MCP2515的复位函数,编写完成如下所示:

struct spi_device *spi_dev; // SPI设备指针// MCP2515芯片复位函数
void mcp2515_reset(void){int ret;char write_buf[] = {0xc0}; // 复位指令0x11000000即0xc0ret = spi_write(spi_dev, write_buf, sizeof(write_buf)); // 发送复位命令if(ret < 0){printk("spi_write is error\n"); // 打印错误信息}
}

由于这里只编写了MCP2515的复位函数,无法进行验证,所以本章节并不能进行相应的实验,在下个小节中将会对SPI通信流程进行讲解。

188.2 SPI通信流程

在上个小节中讲解的spi_write函数可以向SPI从设备发送数据,而spi_read函数可以接收从设备发送的数据,spi_read函数具体内容如下所示:

static inline int
spi_read(struct spi_device *spi, void *buf, size_t len)
{struct spi_transfer	t = {.rx_buf		= buf,.len		= len,};return spi_sync_transfer(spi, &t, 1);
}

跟spi_write函数相同,spi_read函数也会对数据进行封包的操作,将数据buf以及数据大小len封包成spi_transfer类型的结构体,struct spi_transfer是一个描述SPI数据传输的结构体,用于配置一次SPI数据传输的各种参数,该结构体的具体内容如下所示:

struct spi_transfer {const void *tx_buf;    // 发送缓冲区void *rx_buf;          // 接收缓冲区unsigned len;          // 传输数据的长度dma_addr_t tx_dma;     // 发送缓冲区的 DMA 地址dma_addr_t rx_dma;     // 接收缓冲区的 DMA 地址struct sg_table tx_sg; // 发送缓冲区的散列-聚集表struct sg_table rx_sg; // 接收缓冲区的散列-聚集表unsigned cs_change:1;  // 是否在传输后改变片选状态unsigned tx_nbits:3;   // 发送的位数(单线、双线或四线传输)unsigned rx_nbits:3;   // 接收的位数(单线、双线或四线传输)#define SPI_NBITS_SINGLE 0x01 // 1 位传输#define SPI_NBITS_DUAL   0x02 // 2 位传输#define SPI_NBITS_QUAD   0x04 // 4 位传输u8 bits_per_word;     // 每个字的位数u16 delay_usecs;      // 传输之间的延迟(微秒)u32 speed_hz;         // 传输速度(赫兹)u16 word_delay;       // 每个字之间的延迟struct list_head transfer_list; // 传输链表,用于将多个传输串联起来
};

而spi_write函数和spi_read函数只差在struct spi_transfer结构体参数的不同,而封装为struct spi_transfer之后还需要再一次进行封装,spi_write函数和spi_read函数最后都会调用 spi_sync_transfer函数,该函数的具体内容如下所示:

static inline int
spi_sync_transfer(struct spi_device *spi, struct spi_transfer *xfers,unsigned int num_xfers)
{struct spi_message msg;// 使用给定的传输初始化 SPI 消息spi_message_init_with_transfers(&msg, xfers, num_xfers);// 同步方式发送 SPI 消息return spi_sync(spi, &msg);
}

这个函数主要用于封装 SPI 同步传输操作,简化了调用过程。在第8行调用了spi_message_init_with_transfers函数进行SPI传输数据的初始化,最后在第11行调用spi_sync函数采用同步的方式发送SPI数据,spi_sync函数的具体内容如下所示:

int spi_sync(struct spi_device *spi, struct spi_message *message)
{int ret;// 锁定 SPI 控制器的总线锁互斥体mutex_lock(&spi->controller->bus_lock_mutex);// 执行同步 SPI 传输ret = __spi_sync(spi, message);// 解锁 SPI 控制器的总线锁互斥体mutex_unlock(&spi->controller->bus_lock_mutex);return ret;
}

该函数的主要作用是确保SPI数据传输操作在一个互斥锁的保护下进行,以避免并发传输导致的冲突和数据错误。通过调用内部的 __spi_sync 函数来执行实际的数据传输。__spi_sync函数如下所示:

static int __spi_sync(struct spi_device *spi, struct spi_message *message)
{// 声明并初始化一个完成变量DECLARE_COMPLETION_ONSTACK(done);int status;struct spi_controller *ctlr = spi->controller;unsigned long flags;// 验证 SPI 设备和消息status = __spi_validate(spi, message);if (status != 0)return status;// 设置消息完成回调和上下文message->complete = spi_complete;message->context = &done;message->spi = spi;// 更新统计信息SPI_STATISTICS_INCREMENT_FIELD(&ctlr->statistics, spi_sync);SPI_STATISTICS_INCREMENT_FIELD(&spi->statistics, spi_sync);/* 如果我们不使用旧的传输方法,* 那么我们将在调用上下文中尝试传输以进行特殊处理。* 如果我们能够删除对驱动程序实现的消息队列的支持,这段代码会更简单。*/if (ctlr->transfer == spi_queued_transfer) {// 锁定总线锁旋转锁并保存中断标志spin_lock_irqsave(&ctlr->bus_lock_spinlock, flags);// 记录 SPI 消息提交的跟踪信息trace_spi_message_submit(message);// 执行队列传输status = __spi_queued_transfer(spi, message, false);// 解锁总线锁旋转锁并恢复中断标志spin_unlock_irqrestore(&ctlr->bus_lock_spinlock, flags);} else {// 异步锁定传输status = spi_async_locked(spi, message);}if (status == 0) {/* 如果可以,则在调用上下文中推送消息 */if (ctlr->transfer == spi_queued_transfer) {// 更新同步立即传输的统计信息SPI_STATISTICS_INCREMENT_FIELD(&ctlr->statistics, spi_sync_immediate);SPI_STATISTICS_INCREMENT_FIELD(&spi->statistics, spi_sync_immediate);// 推送消息__spi_pump_messages(ctlr, false);}// 等待完成wait_for_completion(&done);// 获取消息的状态status = message->status;}// 清除消息的上下文message->context = NULL;return status;
}

该函数的主要作用是在锁定的上下文中同步执行SPI消息传输。它负责初始化传输消息,验证消息和设备的有效性,处理传输,并在完成后返回传输的状态。该函数的重点在__spi_pump_messages推送消息函数,该函数的具体内容如下所示:

static void __spi_pump_messages(struct spi_controller *ctlr, bool in_kthread)
{unsigned long flags;bool was_busy = false;int ret;/* 锁定消息队列 */spin_lock_irqsave(&ctlr->queue_lock, flags);/* 确保没有其他消息正在处理 */if (ctlr->cur_msg) {spin_unlock_irqrestore(&ctlr->queue_lock, flags);return;}/* 如果另一个上下文正在空闲设备,则推迟处理 */if (ctlr->idling) {kthread_queue_work(&ctlr->kworker, &ctlr->pump_messages);spin_unlock_irqrestore(&ctlr->queue_lock, flags);return;}/* 检查队列是否空闲 */if (list_empty(&ctlr->queue) || !ctlr->running) {if (!ctlr->busy) {spin_unlock_irqrestore(&ctlr->queue_lock, flags);return;}/* 只有在线程中执行拆除操作 */if (!in_kthread) {kthread_queue_work(&ctlr->kworker,&ctlr->pump_messages);spin_unlock_irqrestore(&ctlr->queue_lock, flags);return;}ctlr->busy = false;ctlr->idling = true;spin_unlock_irqrestore(&ctlr->queue_lock, flags);kfree(ctlr->dummy_rx);ctlr->dummy_rx = NULL;kfree(ctlr->dummy_tx);ctlr->dummy_tx = NULL;if (ctlr->unprepare_transfer_hardware &&ctlr->unprepare_transfer_hardware(ctlr))dev_err(&ctlr->dev,"failed to unprepare transfer hardware\n");if (ctlr->auto_runtime_pm) {pm_runtime_mark_last_busy(ctlr->dev.parent);pm_runtime_put_autosuspend(ctlr->dev.parent);}trace_spi_controller_idle(ctlr);spin_lock_irqsave(&ctlr->queue_lock, flags);ctlr->idling = false;spin_unlock_irqrestore(&ctlr->queue_lock, flags);return;}/* 从队列中获取第一个消息 */ctlr->cur_msg =list_first_entry(&ctlr->queue, struct spi_message, queue);list_del_init(&ctlr->cur_msg->queue);if (ctlr->busy)was_busy = true;elsectlr->busy = true;spin_unlock_irqrestore(&ctlr->queue_lock, flags);mutex_lock(&ctlr->io_mutex);if (!was_busy && ctlr->auto_runtime_pm) {ret = pm_runtime_get_sync(ctlr->dev.parent);if (ret < 0) {pm_runtime_put_noidle(ctlr->dev.parent);dev_err(&ctlr->dev, "Failed to power device: %d\n",ret);mutex_unlock(&ctlr->io_mutex);return;}}if (!was_busy)trace_spi_controller_busy(ctlr);if (!was_busy && ctlr->prepare_transfer_hardware) {ret = ctlr->prepare_transfer_hardware(ctlr);if (ret) {dev_err(&ctlr->dev,"failed to prepare transfer hardware\n");if (ctlr->auto_runtime_pm)pm_runtime_put(ctlr->dev.parent);mutex_unlock(&ctlr->io_mutex);return;}}trace_spi_message_start(ctlr->cur_msg);if (ctlr->prepare_message) {ret = ctlr->prepare_message(ctlr, ctlr->cur_msg);if (ret) {dev_err(&ctlr->dev, "failed to prepare message: %d\n",ret);ctlr->cur_msg->status = ret;spi_finalize_current_message(ctlr);goto out;}ctlr->cur_msg_prepared = true;}ret = spi_map_msg(ctlr, ctlr->cur_msg);if (ret) {ctlr->cur_msg->status = ret;spi_finalize_current_message(ctlr);goto out;}ret = ctlr->transfer_one_message(ctlr, ctlr->cur_msg);if (ret) {dev_err(&ctlr->dev,"failed to transfer one message from queue\n");goto out;}out:mutex_unlock(&ctlr->io_mutex);/* 如果成功传输,则唤醒调度器 */if (!ret)cond_resched();
}

124行代码ctlr->transfer_one_message是一个函数指针,它指向了SPI控制器中负责执行SPI消息传输的函数。通过调用这个函数,将当前的SPI消息 ctlr->cur_msg 传递给该函数进行处理。这个函数通常会负责将消息的数据发送到SPI设备或从设备接收数据,并与硬件设备进行通信。

因此,ctlr->transfer_one_message(ctlr, ctlr->cur_msg)这一行代码的作用是将当前的SPI消息传递给SPI控制器中的传输函数进行处理,以完成消息的传输操作。

至此,SPI通信过程已经分析完毕,而除了spi_write和spi_read函数,还有第三个常用函数spi_write_then_read,该函数的作用为先写后读,在后面的章节中会用到该函数,该函数的具体内容如下所示:

int spi_write_then_read(struct spi_device *spi,const void *txbuf, unsigned n_tx,void *rxbuf, unsigned n_rx)
{// 定义一个静态互斥锁static DEFINE_MUTEX(lock);int			status;struct spi_message	message;struct spi_transfer	x[2];u8			*local_buf;/* 如果可以的话,使用预分配的 DMA 安全缓冲区。我们不能避免* 在这里进行拷贝操作(作为一种纯粹的方便操作),但是我们可以* 在缓冲区未被其他进程使用或传输不太大的情况下,* 避免在热路径上分配堆内存。*/if ((n_tx + n_rx) > SPI_BUFSIZ || !mutex_trylock(&lock)) {local_buf = kmalloc(max((unsigned)SPI_BUFSIZ, n_tx + n_rx),GFP_KERNEL | GFP_DMA);if (!local_buf)return -ENOMEM; // 如果内存分配失败,返回错误码} else {local_buf = buf;}// 初始化 SPI 消息spi_message_init(&message);memset(x, 0, sizeof(x));if (n_tx) {x[0].len = n_tx;spi_message_add_tail(&x[0], &message);}if (n_rx) {x[1].len = n_rx;spi_message_add_tail(&x[1], &message);}// 将发送数据复制到本地缓冲区memcpy(local_buf, txbuf, n_tx);x[0].tx_buf = local_buf;x[1].rx_buf = local_buf + n_tx;/* 执行 I/O 操作 */status = spi_sync(spi, &message);if (status == 0)// 如果传输成功,将接收数据复制到接收缓冲区memcpy(rxbuf, x[1].rx_buf, n_rx);// 释放锁或释放内存if (x[0].tx_buf == buf)mutex_unlock(&lock);elsekfree(local_buf);return status; // 返回传输状态
}

至此,关于常用的SPI通信函数以及SPI通信流程就讲解完成了,在下个章节中将会继续对MCP2515驱动程序进行完善。

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

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

相关文章

[数据结构] --- 树

1 树的基本概念 1.1 树的定义 树是n(n>0)个结点的有限集。当 n 0 时&#xff0c;称为空树。在任意一棵树非空树中应满足&#xff1a; (1) 有且仅有一个特定的称为根 (root) 的结点&#xff1b; (2) 当 n > 1 时&#xff0c;其余结点可分为m(m>0)个互不相交的有限集…

GDB 远程调试简介

文章目录 1. 前言2. GDB 远程调试2.1 准备工作2.1.1 准备 客户端 gdb 程序2.1.2 准备 服务端 gdbserver2.1.3 准备 被调试程序 2.2 调试2.2.1 通过网络远程调试2.2.1.1 通过 gdbserver 直接启动程序调试2.2.1.2 通过 gdbserver 挂接到已运行程序调试 2.2.2 通过串口远程调试2.2…

如何快速申请免费SSL证书,实现网站HTTPS安全传输

随着互联网技术的飞速发展&#xff0c;网络安全已成为不可忽视的重要议题。HTTPS协议&#xff0c;作为HTTP协议的安全版本&#xff0c;通过SSL协议加密客户端与服务器之间的数据传输&#xff0c;从而保障信息在传输过程中的安全性。对于网站运营者而言&#xff0c;为网站部署SS…

违规停放智能监测摄像机

对于现代城市管理来说&#xff0c;违规停放智能监测摄像机正逐渐成为解决交通拥堵和城市管理难题的重要工具。这类摄像机通过先进的视觉识别和数据分析技术&#xff0c;有效监控和管理道路上的车辆停放行为&#xff0c;对提升城市交通运行效率和改善市民出行环境具有显著的意义…

三代测序PacBioONT reads过滤和修剪-Chooper

chopper简介 chopper是NanoFilt和NanoLyse的Rust语言版本&#xff0c;适用于长reads测序&#xff08;如PacBio和纳米孔测序ONT&#xff09;的过滤和修剪fastq文件。 chopper相对于python编写的NanoFilt和NanoLyse&#xff0c;运行输出相同结果的时间更短&#xff0c;且NanoFi…

思维,CF 739A - Alyona and mex

一、题目 1、题目描述 2、输入输出 2.1输入 2.2输出 3、原题链接 739A - Alyona and mex 二、解题报告 1、思路分析 我们考虑区间mex运算的值最大也就是区间长度&#xff0c;所以我们最大值的上界就是所有区间中的最小长度&#xff0c;假如记为mi 我们一定可以构造出答案…

zabbix 配置钉钉告警

1.申请一个钉钉企业版 2.群内申请一个机器人 下载电脑版钉钉&#xff0c;登录后&#xff0c;在要接收群消息的群里&#xff0c;点击右上角设置图标&#xff0c;下滑找到机器人&#xff0c;添加一个机器人&#xff0c;保存机器人的webhook地址 保存这里的加签字符串 保存这里的…

通信软件开发之业务知识:PON口割接什么意思?

一 PON口割接&#xff08;原创总结&#xff09; 在通信领域&#xff0c;PON口割接指的是对无源光网络&#xff08;Passive Optical Network&#xff0c;PON&#xff09;端口进行的切换或调整操作。简单来说&#xff0c;就是对光纤网络中的某个端口进行重新连接或重新分配&…

153. 寻找旋转排序数组中的最小值(中等)

153. 寻找旋转排序数组中的最小值 1. 题目描述2.详细题解3.代码实现3.1 Python3.2 Java 1. 题目描述 题目中转&#xff1a;153. 寻找旋转排序数组中的最小值 2.详细题解 如果不考虑 O ( l o g n ) O(log n) O(logn)的时间复杂度&#xff0c;直接 O ( n ) O(n) O(n)时间复杂…

【Hugging Face全面拥抱LangChain:全新官方合作包】

文末有福利&#xff01; ❝ 最近Hugging Face官宣发布langchain_huggingface&#xff0c;这是一个由 Hugging Face 和 LangChain 共同维护的 LangChain 合作伙伴包。这个新的 Python 包旨在将 Hugging Face 最新功能引入 LangChain 并保持同步。 通过Hugging Face官方包的加持&…

14-15 为什么我们现在对阅读如此难以接受

写出来感觉很奇怪&#xff0c;但最近我感觉自己失去了阅读能力。长篇文本对我来说尤其具有挑战性。句子很难读完。更别提章节了。章节有很多段落&#xff0c;而段落又由许多句子组成。 啊。 即使在极少数情况下&#xff0c;我读完了一章&#xff0c;下一页上已经有另一章等着…

有sdwan可以不用专线吗?sdwan和专线的区别优势

SD-WAN&#xff08;Software-Defined Wide Area Network&#xff0c;软件定义广域网&#xff09;确实可以在很大程度上替代传统的专线连接&#xff0c;尤其是在追求成本效益和网络灵活性的场景下。SD-WAN的核心优势在于其智能化和自动化的能力&#xff0c;这使得它能够优化数据…

华清远见人工智能课程:项目优势助力,学习更高效!

在人工智能飞速发展的今天&#xff0c;学习人工智能成为新的高薪赛道。我们都知道人工智能的学习离不开项目练手&#xff0c;只有通过实际项目的操作&#xff0c;才能真正掌握人工智能的核心技能。但遗憾的是&#xff0c;很多人工智能课程只注重理论知识的传授&#xff0c;缺乏…

本地文件上传Github的方法

本文仅用于个人回忆本地文件上传GitHub方法&#xff0c;使用HTTP上传而不是SSH&#xff0c;其余文件已配置完成&#xff0c;如果你和我一样&#xff0c;那么请往下看&#xff0c;这条博客不说废话。 Step1 选择需要上传的文件&#xff0c;右键选择Git Bash Here Step2 创建一…

GAMES104:04游戏引擎中的渲染系统1:游戏渲染基础-学习笔记

文章目录 概览&#xff1a;游戏引擎中的渲染系统四个课时概览 一&#xff0c;渲染管线流程二&#xff0c;了解GPUSIMD 和 SIMTGPU 架构CPU到GPU的数据传输GPU性能限制 三&#xff0c;可见性Renderable可渲染对象提高渲染效率Visibility Culling 可见性裁剪 四&#xff0c;纹理压…

电路模型和电路定律

电路---为了某种需要由某些电工设备或元件按一定方式组合起来的电流的通路 实际电路的两个作用 1.电能的传输&#xff0c;分配和转换 2.传递和处理信号 电路中的几个基本概念 激励---电源或信号源的电压或电流&#xff0c;也称为输入 响应---由激励在电路各部分产生的电流…

怎么参与场外期权?

今天期权懂带你了解怎么参与场外期权&#xff1f; 目前个人投资者暂时还不能直接参与场外个股期权&#xff0c;因为场外个股期权现在只能机构来进行交易。 所以个人投资者目前只能通过机构通道来进行操作&#xff0c;类似期权懂&#xff0c;找到期权懂经理&#xff0c;然后通…

手机删除的照片怎么找回?3个急救指南,让你重新拥有

一不小心手滑&#xff0c;手机里的几百张珍贵照片就消失了&#xff01;是不是心如刀割&#xff0c;感觉错过了几个亿&#xff1f;手机删除的照片怎么找回&#xff1f;别担心&#xff0c;小菜一碟&#xff0c;恢复照片就像打游戏一样&#xff0c;只要掌握正确的“攻略”&#xf…

AI大模型时代来临:企业如何抢占先机?

AI大模型时代来临:企业如何抢占先机? 2023年,被誉为大模型元年,AI大模型的发展如同一股不可阻挡的潮流,正迅速改变着我们的工作和生活方式。从金融到医疗,从教育到制造业,AI大模型正以其强大的生成能力和智能分析,重塑着行业的未来。 智能化:企业核心能力的转变 企…

世界智能产业博览会开幕 - 天空卫士汽车行业方案入选优秀案例

6月20日&#xff0c;以“智行天下、能动未来”为主题的2024世界智能产业博览会在国家会展中心&#xff08;天津&#xff09;开幕。主席向博览会致贺信并指出&#xff1a;中国高度重视人工智能发展&#xff0c;积极推动互联网、大数据、人工智能和实体经济深度融合&#xff0c;培…