[A133]全志u-boot中的I2C驱动分析

[A133]全志u-boot中的I2C驱动分析

hongxi.zhu

2024-6-27

一、IIC标准读写时序

在这里插入图片描述

IIC是高位(MSB)先传输

二、代码流程

2.1主机写数据

brandy/brandy-2.0/u-boot-2018/drivers/i2c/sunxi_i2c.c

static int sunxi_i2c_write(struct i2c_adapter *adap, uint8_t chip,
				uint32_t addr, int alen, uint8_t *buffer, int len)
{
	int ret;

	ret = twi_start(adap->hwadapnr);  // 主机发开始信号
	if (ret) {
		I2C_ERR("twi_write start error\n");
		goto i2c_write_err_occur;
	}

	ret = twi_send_slave_addr(adap->hwadapnr, chip, I2C_WRITE);  // 主机发从机设备地址
	if (ret) {
		I2C_ERR("twi_write send slave addr error!\n");
		goto i2c_write_err_occur;
	}

	ret = twi_send_addr(adap->hwadapnr, addr, alen);  // 主机发送从机寄存器地址
	if (ret) {
		I2C_ERR("twi_write send addr error!\n");
		goto i2c_write_err_occur;
	}

	ret = twi_send_data(adap->hwadapnr, buffer, len);  //主机发送数据到从机
	if (ret) {
		I2C_ERR("twi_write send data error!\n");
		goto i2c_write_err_occur;
	}

i2c_write_err_occur:
	twi_stop(adap->hwadapnr);  // 主机发送Stop信号
	return ret;

}
2.1.1 主机发开始信号
static int twi_start(int bus_num)
{
	u32 timeout = MAX_SUNXI_I2C_TIMEOUT;

	twi_soft_reset(bus_num);  //重置TWI_EFR[1:0]寄存器和TWI_SRST[0]寄存器实现软复位
	twi_set_start(bus_num);  //发送START信号,设置TWI_CNTR[5]为1

    //发送START信号成功会触发中断,判断TWI_CNTR[3]寄存器的INT_FLAG位是否为1
	if (twi_wait_irq_flag(bus_num, timeout)) {
		I2C_ERR("START can't sendout!\n");
		return SUNXI_I2C_FAIL;
	}

    // 判断START信号是否正常发出,读取TWI_STAT[7:0]是否为0x08(START condition transmitted)
	if (twi_wait_status(bus_num, I2C_START_TRANSMIT, timeout))
		return SUNXI_I2C_FAIL;

	return SUNXI_I2C_OK;
}
2.1.2 主机发从机设备地址
static int twi_send_slave_addr(int bus_num, u32 saddr,  u32 rw)
{
	u32 timeout = MAX_SUNXI_I2C_TIMEOUT;
	struct sunxi_twi_reg *i2c = sunxi_i2c[bus_num];

	rw &= 1;
	i2c->data = ((saddr & 0xff) << 1) | rw;  //将7-bit地址写到高7位, 并将读写位设为I2C_WRITE(0)
	twi_clear_irq_flag(bus_num);  //清除当前总线的中断标志, TWI_CNTR[3] INT_FLAG = 0 (全志这里写的有问题)

	if (twi_wait_irq_flag(bus_num, timeout)) // 等待从机地址发送完成中断
		return SUNXI_I2C_TOUT;

	if ((rw == I2C_WRITE) && (twi_wait_status(bus_num, I2C_ADDRWRITE_ACK, timeout)))
		return SUNXI_I2C_FAIL;
	else if ((rw == I2C_READ) && (twi_wait_status(bus_num, I2C_ADDRREAD_ACK, timeout)))
		return SUNXI_I2C_FAIL;

	return SUNXI_I2C_OK;
}
2.1.3 主机发送从机寄存器地址
static int twi_send_addr(int bus_num, uint addr, int alen)
{
	int i, ret, addr_len;
	char *slave_reg;

	if (alen >= 3)
		addr_len = 2;
	else if (alen <= 1)
		addr_len = 0;
	else
		addr_len = 1;

	slave_reg = (char *)&addr;

	for (i = addr_len; i >= 0; i--) {
        // 1. 发送寄存器地址数据
        // 2. 等待中断
        // 3. 判断状态寄存器值 == 0x28,即发送成功且收到从机ACK
		ret = twi_send_byte_addr(bus_num, slave_reg[i] & 0xff);

		if (ret != SUNXI_I2C_OK)
			goto twi_send_addr_err;
	}

twi_send_addr_err:
	return ret;

}
2.1.4 主机发送数据到从机
static int twi_send_data(int bus_num, u8  *data_addr, u32 data_count)
{
	u32 timeout = MAX_SUNXI_I2C_TIMEOUT;
	u32  i;
	struct sunxi_twi_reg *i2c = sunxi_i2c[bus_num];

	for (i = 0; i < data_count; i++) {
		i2c->data = data_addr[i];
		twi_clear_irq_flag(bus_num);  //清中断

		if (twi_wait_irq_flag(bus_num, timeout))  //等待发送完成中断
			return SUNXI_I2C_TOUT;

		if (twi_wait_status(bus_num, I2C_DATAWRITE_ACK, timeout))  //等待状态寄存器值变为0x28,即发送成功且收到从机ACK
			return SUNXI_I2C_FAIL;
	}

	return SUNXI_I2C_OK;
}
2.1.5主机发送Stop信号
static int twi_stop(int bus_num)
{
	u32 timeout = MAX_SUNXI_I2C_TIMEOUT;
	struct sunxi_twi_reg *i2c = sunxi_i2c[bus_num];

	i2c->ctl |= (0x01 << 4);  //清除TWI_CNTR[4]位 (全志这里的操作有点问题)
	i2c->ctl |= (0x01 << 3);  //清中断 (全志这里的操作有点问题)

	twi_set_stop(bus_num);  // 设置TWI_CNTR[4]寄存器,发出stop信号
	twi_clear_irq_flag(bus_num); //清中断 (全志这里的操作有点问题)

	if (twi_wait_status(bus_num, TWI_STAT_IDLE, timeout))  //等待总线进入idle状态
		return SUNXI_I2C_TFAIL;

	return SUNXI_I2C_OK;
}

2.2 主机读数据

brandy/brandy-2.0/u-boot-2018/drivers/i2c/sunxi_i2c.c

static int sunxi_i2c_read(struct i2c_adapter *adap, uint8_t chip,
				uint32_t addr, int alen, uint8_t *buffer, int len)
{
	int  ret;

	ret = twi_start(adap->hwadapnr);  // 主机发开始信号
	if (ret) {
		I2C_ERR("twi_read start error\n");
		goto i2c_read_err_occur;
	}

	ret = twi_send_slave_addr(adap->hwadapnr, chip, I2C_WRITE);  // 主机发从机设备地址
	if (ret){
		I2C_ERR("twi_read send slave addr error!\n");
		goto i2c_read_err_occur;
	}

	ret = twi_send_addr(adap->hwadapnr, addr, alen);    // 主机发送从机寄存器地址
	if (ret) {
		I2C_ERR("twi_read send addr error\n");
		goto i2c_read_err_occur;
	}

	ret = twi_restart(adap->hwadapnr);  // 主机发送restart信号(或者start信号)
	if (ret) {
		I2C_ERR("twi_restart error\n");
		goto i2c_read_err_occur;
	}

	ret = twi_send_slave_addr(adap->hwadapnr, chip, I2C_READ);  // 主机发从机设备地址
	if (ret) {
		I2C_ERR("twi_read send slave addr error!\n");
		goto i2c_read_err_occur;
	}

	ret = twi_get_data(adap->hwadapnr, buffer, len);  // 主机读取从机发送的数据
	if (ret) {
		I2C_ERR("twi_get_data error\n");
		goto i2c_read_err_occur;
	}

i2c_read_err_occur:
	twi_stop(adap->hwadapnr);   // 主机发送Stop信号
	return ret;

}

读操作除了下面的两个操作,其他与写一样

2.2.1 主机发送restart信号(或者start信号)
static int twi_start(int bus_num)
{
	u32 timeout = MAX_SUNXI_I2C_TIMEOUT;

	twi_soft_reset(bus_num);
	twi_set_start(bus_num);

	if (twi_wait_irq_flag(bus_num, timeout)) {
		I2C_ERR("START can't sendout!\n");
		return SUNXI_I2C_FAIL;
	}

	if (twi_wait_status(bus_num, I2C_START_TRANSMIT, timeout))
		return SUNXI_I2C_FAIL;

	return SUNXI_I2C_OK;
}

static int twi_restart(int bus_num)
{
	u32 timeout = MAX_SUNXI_I2C_TIMEOUT;

	twi_set_start(bus_num);
	twi_clear_irq_flag(bus_num);
	if (twi_wait_irq_flag(bus_num, timeout)) {
		I2C_ERR("Restart can't sendout!\n");
		return SUNXI_I2C_FAIL;
	}

	if (twi_wait_status(bus_num, I2C_RESTART_TRANSMIT, timeout))
		return SUNXI_I2C_FAIL;

	return SUNXI_I2C_OK;
}

restart信号实际上就是start信号,只是restart不会reset总线

start: 重置SCL和SDA到IDLE状态,即两者都为高,此时只需要操作SDA拉低,做出一个SDA下降沿就完成start信号

restart:不重置SCL和SDA,但是主动拉高SDA到高电平,直到下一个SCL高电平时钟周期到来后做出下降沿

2.2.2 主机读取从机数据
static int twi_get_data(int bus_num, u8 *data_addr, u32 data_count)
{
	u32 timeout = MAX_SUNXI_I2C_TIMEOUT;
	u32  i;
	struct sunxi_twi_reg *i2c = sunxi_i2c[bus_num];

    // 最后一个字节不需要发送ACK到从机, 而是发送NACK
    
	if (data_count == 1) {  //如果只有一个字节,那它就是最后一个字节。
		/* no need ack  */
		twi_clear_irq_flag(bus_num);

		if (twi_wait_irq_flag(bus_num, timeout))
			return SUNXI_I2C_TOUT;

		if (twi_wait_status(bus_num, I2C_DATAREAD_NACK, timeout)) // 等待TWI_STAT[7:0]的状态位变为I2C_DATAREAD_NACK
			return SUNXI_I2C_FAIL;

		*data_addr = i2c->data;  //从TWI_DATA[7:0]读取一个字节的数据
	} else {
		for (i = 0; i < data_count - 1; i++) {  //非最后一个字节需要向从机发ACK
			/* need ack  */
			twi_enable_ack(bus_num);  // 设TWI_CNTR[2]为1
			twi_clear_irq_flag(bus_num);

			if (twi_wait_irq_flag(bus_num, timeout))
				return SUNXI_I2C_TOUT;

			if (twi_wait_status(bus_num, I2C_DATAREAD_ACK, timeout))   等待TWI_STAT[7:0]的状态位变为I2C_DATAREAD_ACK
				return SUNXI_I2C_FAIL;

			data_addr[i] = i2c->data;  //从TWI_DATA[7:0]读取一个字节的数据
		}

		/* received the last byte  */
		twi_disable_ack(bus_num);  // 设TWI_CNTR[2]为0
		twi_clear_irq_flag(bus_num);

		if (twi_wait_irq_flag(bus_num, timeout))
			return SUNXI_I2C_TOUT;

		if (twi_wait_status(bus_num, I2C_DATAREAD_NACK, timeout)) // 等待TWI_STAT[7:0]的状态位变为I2C_DATAREAD_NACK
			return SUNXI_I2C_FAIL;

		data_addr[data_count - 1] = i2c->data;  //从TWI_DATA[7:0]读取一个字节的数据
	}

	return SUNXI_I2C_OK;
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

深入解析 androidx.databinding.BaseObservable

在现代 Android 开发中&#xff0c;数据绑定 (Data Binding) 是一个重要的技术&#xff0c;它简化了 UI 和数据之间的交互。在数据绑定框架中&#xff0c;androidx.databinding.BaseObservable 是一个关键类&#xff0c;用于实现可观察的数据模型。本文将详细介绍 BaseObservab…

Centos7安装Minio笔记

一、Minio概述 Minio是一款开源的对象存储服务器&#xff0c;可以运行在多种操作系统上&#xff0c;包括Linux、Windows和MacOS等。提供一种简单、可扩展、高可用的对象存储解决方案&#xff0c;支持多种数据格式&#xff0c;包括对象、块和文件等。Minio是一款强大、灵活、可…

基于若依(ruoyi-vue)的周报管理系统

喂wangyinlon 填报人页面 审批人 审批不通过,填报人需要重新填写.

智慧校园新气象:校园气象站

在数字化、智能化的浪潮下&#xff0c;传统校园正在迎来一场革命性的变革。在这场变革中&#xff0c;校园气象站以其独特的功能和魅力&#xff0c;成为推动校园气象科普教育、提升校园品质的重要力量。 一、校园气象站&#xff1a;智慧校园的“气象眼” 校园气象站&#xff0c…

宠物医院管理系统-计算机毕业设计源码07221

目 录 1 绪论 1.1 选题背景和意义 1.2国内外研究现状 1.3论文结构与章节安排 2 宠物医院管理系统系统分析 2.1 可行性分析 2.1.1技术可行性分析 2.1.2 操作可行性分析 2.1.3 法律可行性分析 2.2 系统功能分析 2.2.1 功能性分析 2.2.2 非功能性分析 2.3 系统用例分…

Ansible 最佳实践:现代 IT 运维的利器

Ansible 最佳实践&#xff1a;现代 IT 运维的利器 Ansible 是一种开源的 IT 自动化工具&#xff0c;通过 SSH 协议实现远程节点和管理节点之间的通信&#xff0c;适用于配置管理、应用程序部署、任务自动化等多个场景。本文将介绍 Ansible 的基本架构、主要功能以及最佳实践&a…

为什么80%的码农都做不了架构师?

文章目录 一、技术广度和深度的要求1.1 技术广度1.2 技术深度 二、全局视角和系统思维2.1 全局视角2.2 系统思维 三、沟通能力和团队合作3.1 沟通能力3.2 团队合作 四、业务理解和需求分析4.1 业务理解4.2 需求分析 五、持续学习和创新能力5.1 持续学习5.2 创新能力 六、总结 &…

鸿蒙:页面路由使用

页面路由使用步骤&#xff1a; 1.导入Router模块 2.使用路由功能&#xff0c;以pushUrl模式为例 3.接收参数、返回 4.此时的路由是不能使用的&#xff0c;需要到main_pages.json中进行注册

FFmpeg视频处理工具安装使用

一、前言 FFmpeg是流行的开源视频处理工具&#xff0c;用于转码、合并、编辑等。以下是安装和使用方法&#xff1a; 二、步骤 1.下载 1.1 ffmpeg下载 官网下载地址 wget https://www.ffmpeg.org/releases/ffmpeg-6.1.1.tar.xz1.2 nasm下载 https://www.nasm.us/pub/nasm/…

PHP安龙县农产品销售网站-计算机毕业设计源码13137

目 录 摘要 1 绪论 1.1 研究背景 1.2 研究意义 1.3论文结构与章节安排 2 相关技术介绍 2.1 PHP描述 2.2 MySQL数据库 2.3 Think PHP框架 3网站分析 3.1 可行性分析 3.2 网站流程分析 3.2.1 数据新增流程 3.2.2 数据删除流程 3.3 网站功能分析 3.3.1 功能性分析…

VSCode创建并运行html页面(使用Live Server插件)

目录 一、参考博客二、安装Live Server插件三、新建html页面3.1 选择文件夹3.2 新建html文件3.3 快速生成html骨架 四、运行html页面 一、参考博客 https://blog.csdn.net/zhuiqiuzhuoyue583/article/details/126610162 https://blog.csdn.net/m0_74014525/article/details/13…

偏微分方程算法之抛物型方程差分格式编程示例八(紧交替方向隐格式)

目录 一、研究问题 二、C++代码 三、计算结果 一、研究问题 示例七中采用交替方向格式进行抛物型方程求解,这里继续以紧交替方向隐格式对相同的问题进行求解。 紧交替方向隐格式的原理及推导请参考: 偏微分方程算法之二维初边值问题(紧交替方向隐格式)_二维抛物方程的p…

Kafka-时间轮和延迟操作-源码流程

TimingWheel 字段&#xff1a; buckets&#xff1a;Array.tabulate[TimerTaskList]类型&#xff0c;其每一个项都对应时间轮中的一个时间格&#xff0c;用于保存 TimerTaskList的数组。在TimingWheel中&#xff0c;同一个TimerTaskList中的不同定时任务的到期时间可能 不同&a…

小型语言模型的兴起

过去几年&#xff0c;我们看到人工智能能力呈爆炸式增长&#xff0c;其中很大一部分是由大型语言模型 (LLM) 的进步推动的。GPT-3 等模型包含 1750 亿个参数&#xff0c;已经展示了生成类似人类的文本、回答问题、总结文档等能力。然而&#xff0c;虽然 LLM 的能力令人印象深刻…

海洋海事NEMA2000耐腐蚀不锈钢航空插头插座

海洋海事NEMA2000耐腐蚀不锈钢航空插头插座是为适应海洋环境中船舶使用的特殊要求而设计的。这类插头插座不仅要满足基本的电气连接功能&#xff0c;还要具备耐海水腐蚀、防水、防尘、防震等特性&#xff0c;以确保在恶劣的海上环境下仍能保持稳定的性能。 NMEA 2000插头插座的…

cesium自定义弹框

token记得换成您自己的&#xff01;&#xff01;&#xff01; 申请cesium的token 官网【Cesium: The Platform for 3D Geospatial】 pickEllipsoid在加载地形的情况下有一定误差&#xff0c;地形凹凸程度越大&#xff0c;误差越大。 pickPosition在depthTestAgainstTerrain …

3-数据提取方法1(json)(6节课学会爬虫)

3-数据提取方法1&#xff08;json&#xff09;&#xff08;6节课学会爬虫&#xff09; 1&#xff0c;Json2&#xff0c;哪里会返回json的数据&#xff08;值得尝试的操作&#xff09;3&#xff0c;Json字符串转换成字典或python类型进行数据提取&#xff08;1&#xff09;Json.…

人脸特征68点识别 C++

1、加载一张图片 main函数&#xff1a; cv::Mat img cv::imread("5.jpg");vector<Point2f> points_vec dectectFace68(img);2、人脸68特征识别函数 在这里vector<Point2f> dectectFace68(Mat src) {vector<Point2f> points_vec;int* pResults …

从0到1搭建微服务框架

目录 1.技术栈&#xff1a; 2.模块介绍: 3.关键代码讲解 3.1基础公共模块(common)依赖&#xff1a; 3.3授权模块(auth)依赖: 3.4授权模块核心配置类(AuthrizatonConfig): 3.4 SecurityConfig.java 3.5 bootstrap的核心配置文件(其他服务配置类似这个)&#xff1a; 3.6n…

视频编解码从H.264到H.266:浅析GB28181安防视频汇聚EasyCVR视频压缩技术

随着信息技术的飞速发展&#xff0c;视频编解码技术也在不断革新&#xff0c;以适应高清、超高清甚至8K视频时代的到来。视频编解码技术作为数字多媒体领域的核心技术之一&#xff0c;也在不断地演进和革新。从早期的H.261到现在的H.265、H.266&#xff0c;每一次技术的升级都极…