RK3588 添加I2C模拟芯片CH423

news2024/12/23 9:47:18

一.简介

有时候会遇到IO不够用的情况,例如说驱动LED灯,那么有没有什么便宜的,容易买到的芯片?我这次就考虑使用WCH的CH423S,这是一个比较新的IO扩展芯片。

二.硬件原理图

使用gpio来模拟IIC,飞线处理:IO_SDA_ctl链接GPIO3_B2  IO_SCL_ctl链接GPIO4_ B6。

三.添加设备树节点

ch423: ch423@40{
     status ="okay";
     compatible ="ch423";
     ch423-clk-gpios =<&gpio3 RK PB2 GPIO ACTIVE HIGH>;
     ch423-dat-gpios= <&gpio4 RK_PB6 GPIO ACTIVE_HIGH>;
}

使用gpio命令查看,两个模拟gpio iic模拟脚已经注册成功。 

四.模拟iic伪代码

#define DELAY 1
typedef unsigned char u8;
typedef unsigned short u16;
 
 
/* 这些代码是框架,直接使用即可 */
 
 
// 定义一个延时xms毫秒的延时函数
void delay(unsigned int xms)  // xms代表需要延时的毫秒数
{
    unsigned int x,y;
    for(x = xms; x > 0; x--)
        for(y = 110; y > 0; y--);
}
 
 
 
 
/******************************start*****************************************/
static void i2c_start(void)
{
	gpio_direction_output(SDA_PIN, 1);
	gpio_direction_output(CLK_PIN, 1);
	delay(DELAY);
	gpio_set_value(SDA_PIN, 0);
	delay(DELAY);
	gpio_set_value(CLK_PIN, 0);
	delay(DELAY);
	
}
 
 
 
 
 
/**********************************************stop****************************************/
static void i2c_stop(void)
{
	gpio_set_value(CLK_PIN, 0);
	gpio_set_value(SDA_PIN, 0);
	delay(DELAY);
 
	gpio_set_value(CLK_PIN, 1);
	delay(DELAY);
	gpio_set_value(SDA_PIN, 1);
	delay(DELAY);
 
}
 
 
 
 
/********************************send_ack****************************************/
/* 参数ack为1时发送NACK,参数ack为0时表示发送ACK */
static void i2c_send_ack(u8 ack)
{
	if(ack)
		gpio_direction_output(SDA_PIN, 1);
	else
		gpio_direction_output(SDA_PIN, 0);
	delay(DELAY);
 
	gpio_set_value(CLK_PIN, 1);
	delay(DELAY);
	gpio_set_value(CLK_PIN, 0);
	delay(DELAY);
}
 
 
 
 
 
/********************************receive_ack*********************************/
/* 返回1表示无效ACK,返回0表示有效ACK */
static u8 i2c_receive_ack(void)
{
	u8 rc = 0;
	gpio_direction_input(SDA_PIN);
	gpio_set_value(CLK_PIN, 1);
	delay(DELAY);
 
	/* 获取ack信号,如果信号为低,则为有效ACK */
	if(gpio_get_value(SDA_PIN))
	{
		rc = 1;
	}
	gpio_set_value(CLK_PIN, 0);
	gpio_direction_output(SDA_PIN, 1);
	return rc;
}
 
 
 
 
/********************************send****************************************/
/* 返回值为0,表示接收到ACK信号,表示发送成功
 * 返回值为1,表示没有收到ACK信号,表示发送失败
 */
static u8 i2c_send_byte(u8 send_byte)
{
	u8 rc = 0;
	u8 out_mask = 0x80;
	u8 value;
	u8 count = 8;
	while(count > 0)
	{
		value = ((send_byte & out_mask) ? 1 : 0);
		if (value == 1) 
		{
			gpio_set_value(SDA_PIN, 1);
		}
		else 
		{
			gpio_set_value(SDA_PIN, 0);
		}
		delay(DELAY);
 
		gpio_set_value(CLK_PIN, 1);
		delay(DELAY);
		gpio_set_value(CLK_PIN, 0);
		delay(DELAY);
		out_mask >>= 1;
		count--;
	}
 
	gpio_set_value(SDA_PIN, 1);
	rc = i2c_receive_ack();
	return rc;
}
 
 
 
 
 
/**********************************************receive*************************************/
static void i2c_read_byte(u8 *buffer, u8 ack)
{
	u8 count = 0x08;
	u8 data = 0x00;
	u8 temp = 0;
 
	gpio_direction_input(SDA_PIN);
	while(count > 0) 
	{
		gpio_set_value(CLK_PIN, 1);
		delay(DELAY);
		temp = gpio_get_value(SDA_PIN);
		data <<= 1;
		if (temp)
		data |= 0x01;
		gpio_set_value(CLK_PIN, 0);
		delay(DELAY);
		count--;
	}
	i2c_send_ack(ack);//0 = ACK, 1 = NACK
	*buffer = data;
}
 
 
 
 
 
 
//向client的某个寄存器写入多个字节,len是要写入的数据的长度??? 
/***********************************************write_bytes********************************/
/* 返回值为0表示收到ACK信号,发送成功
 * 返回值为1表示没有收到ACK信号,发送失败
 */
static u8 i2c_write(u8 device_id, u8 reg_address, u8* data, u8 len)
{
	u8 rc = 0;
	u8 i;
	i2c_start();
 
	rc |= i2c_send_byte( (device_id << 1) | 0x00 );
	if ( 0 != rc )
	{
		printf("i2c_send_byte failed, no ack back\n");
		return rc;
	}
	delay(10);
 
	rc |= i2c_send_byte(reg_address);
	if ( 0 != rc )
	{
		printf("i2c_send_byte failed, no ack back\n");
		return rc;
	}
	delay(10);
 
	if(data==NULL ||0==len)
	{
		i2c_stop();
		return rc;
	}
	delay(10);
 
	for(i=0; i<len; i++) 
	{
		rc |= i2c_send_byte(*data);		
		delay(10);
		if ( 0 != rc )
		{
			printf("i2c_send_byte failed, no ack back\n");
			return rc;
		}
		
		data++;
	}
 
	i2c_stop();
 
	return rc;
}
 
 
 
 
//从某个register中读取len个字节放在长度为len的缓冲区buffer中??? 
/***********************************************read_bytes********************************/
/* 返回值为0表示收到ACK信号,发送成功
 * 返回值为1表示没有收到ACK信号,发送失败
 */
static u8 i2c_read(u8 device_id, u8 reg_address, u8 *buffer, u16 len)
{
	u8 rc = 0;
	u16 i;
	i2c_start();
	rc |= i2c_send_byte( (device_id << 1) | 0x00 );
	if ( 0 != rc )
	{
		printf("i2c_send_byte failed, no ack back\n");
		return rc;
	}
	delay(10);
	rc |= i2c_send_byte(reg_address);
	if ( 0 != rc )
	{
		printf("i2c_send_byte failed, no ack back\n");
		return rc;
	}
	
	delay(10);
	i2c_start();//restart I2C
	rc |= i2c_send_byte( (device_id << 1) | 0x01 );
	if ( 0 != rc )
	{
		printf("i2c_send_byte failed, no ack back\n");
		return rc;
	}
	
	delay(10);
	for(i=0;i<len;i++) 
	{
		i2c_read_byte(buffer++, !(len-i-1));// !(len-i-1)? 这个用来保证在读到每个字节后发送一个ACK并能在最后一个字节读完后发送一个NACK
		delay(10);
 
	}
 
	i2c_stop();
	return rc;
}
 
 
 
 
 
/* 设置gpio为输出功能,并且设置输出值为value */
static void gpio_direction_output(unsigned int gpio, int value)
{
 
    //实现具体平台的代码
}
 
 
/* 设置gpio为输入功能 */
static void gpio_direction_input(unsigned int gpio)
{
 
    //实现具体平台的代码
}
 
 
 
/* 设置gpo的值为value */
static void gpio_set_value(unsigned int gpio, int value)
{
    //实现具体平台的代码
	
}
 
 
//返回gpio的值
static unsigned int gpio_get_value(unsigned int gpio)
{
    //实现具体平台的代码
 
}

五.log分析

模拟IIC一直返回ACK为1.

ACK返回1,说明IIC没有写进去,获取不到IIC的返回值。

六.使用逻辑分析仪解析IIC时序

逻辑分析仪使用链接:

第十三章 Kingst VIS逻辑分析仪的使用_la1010软件_KermanXin的博客-CSDN博客

注意需要选择好解析器的类型:

发现解析不到IIC时序,应该波形有问题。

确认IIC波形:

发现IIC的波形颠倒了,把data引脚和clk引脚的GPIO交换试一下。

ch423: ch423@401{
     status ="okay";
     compatible ="ch423":
     ch423-dat-gpios = <&gpio3 RK PB2 GPIO ACTIVE HIGH>;
     ch423-clk-gpios = <&gpio4 RK PB6 GPIO ACTIVE HIGH>;
}

此时没有报ACK错误,IIC时序正确,IIC写入成功。

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

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

相关文章

2020-2023中国高等级自动驾驶产业发展趋势研究-概念界定

1.1 概念界定 自动驾驶发展过程中&#xff0c;中国出现了诸多专注于研发L3级以上自动驾驶的公司&#xff0c;其在业界地位也越来越重要。本报告围绕“高等级自动驾驶” 展开&#xff0c;并聚焦于该技术2020-2023年在中国市场的变化趋势进行研究。 1.1.1 什么是自动驾驶 自动驾驶…

发现matplotlib的一个问题

今天在做需求的时候发现一个问题&#xff0c;就是当传一个‘o’时&#xff0c;调用plt.plot画图会自动成为散点图&#xff0c;而不是折线图&#xff0c;代码如下&#xff1a; import pandas as pd import numpy as np import matplotlib.pyplot as plt ds pd.date_range(star…

直播视频处理过程

视频其实就是快速播放一连串连续的图片。 每一张图片&#xff0c;我们称为一帧。只要每秒钟帧的数据足够多&#xff0c;也即播放得足够快。比如每秒 30 帧&#xff0c;以人的眼睛的敏感程度&#xff0c;是看不出这是一张张独立的图片的&#xff0c;这就是我们常说的帧率&#…

JavaScript 中的 `this` 指向问题与其在加密中的应用

JS中的 this 关键字是一个非常重要的概念&#xff0c;它在不同情况下会指向不同的对象或值。在本文中&#xff0c;我们将深入探讨 JavaScript 中 this 的各种情况&#xff0c;并思考如何将其应用于 JS加密中的一些有趣用途。 1. 全局上下文中的 this 在全局上下文中&#xff…

cs224w_colab3_2023 And cs224w_colab4_2023学习笔记

class GNNStack(torch.nn.Module):def __init__(self, input_dim, hidden_dim, output_dim, args, embFalse):super(GNNStack, self).__init__() #这里的继承表示参见 https://blog.csdn.net/wanzew/article/details/106993425 # 继承时运行继承类别的函数 总之 __mro__的目的…

C++ 太卷,转 Java?

最近看到知乎、牛客等论坛上关于 C 很多帖子&#xff0c;比如&#xff1a; 2023年大量劝入C 2023年还建议走C方向吗&#xff1f; 看了一圈&#xff0c;基本上都是说 C 这个领域唯一共同点就是都使用 C 语言&#xff0c;其它几乎没有相关性。 的确是这样&#xff0c;比如量化交…

解决IDEA actiBPM插件之.bpmn文件中文乱码

1、修改IDEA编辑器编码为utf8&#xff0c;File->Settings->Editor->File Encodings&#xff0c;都改为UTF-8 2、在IDEA安装bin目录下&#xff0c;找到 idea.exe.vmoptions 和 idea64.exe.vmoptions 两个文件&#xff0c;打开编辑分别在文本最末端添加下面代码&#xf…

postman接口传参案例

目录 案例1&#xff1a; 接口A 接口B 案例2&#xff1a; //断言 案例1&#xff1a; 接口A 根据返回值需要从返回值中提取userid值&#xff0c;在Tests标签栏下编写脚本 //获取返回的响应值&#xff0c;并转化为json格式 var jsonData pm.response.json(); // 获取返回…

AIGC(生成式AI)试用 5 -- 从模糊到精确,再一步

参考 AIGC&#xff08;生成式AI&#xff09;试用 4 -- 从模糊到精确_Rolei_zl的博客-CSDN博客 提问信息不足时&#xff0c;生成式AI有的会引导提问者给出更多信息&#xff0c;有的会按自己的理解给出一个在某些方面正确的答案 随着提供的信息越来越多&#xff0c;生成式AI给…

E-kit 一体化电子工具箱

详细请见&#xff1a; E-kit: E-kit 一体化电子工具箱 (github.com) 在个人博客页查看本文 E-kit E-kit 一体化电子工具箱&#xff0c;STM32 实现&#xff0c;示波器 函数发生器 幅频特性仪器… 目前此项目已归档 注意&#xff1a;工程采用 GB2312 编码 基本功能 STM32F1…

RabbitMQ:基于DelayExchange插件实现延迟队列

因为延迟队列的需求非常多&#xff0c;所以RabbitMQ的官方也推出了一个插件&#xff0c;原生支持延迟队列效果。 这个插件就是DelayExchange插件。参考RabbitMQ的插件列表页面&#xff1a;Community Plugins — RabbitMQ 使用方式可以参考官网地址&#xff1a;Scheduling Mes…

OPC UA协议报文,基础介绍+Hello报文解析

消息主要分为&#xff1a;消息头和附加字段 通讯过程 协议标准第一部分进行总体介绍&#xff1b;协议标准第四部分有详细介绍通讯过程 流程介绍 整体流程 连接套接字》Hello》打开安全信道》创建会话》关闭安全信道》关闭套接字 订阅等事件 服务器审核行为 聚合的服务器审…

你已经应用了哪种服务注册和发现的模式呢?

前面历史文章中我们有说过关于微服务的注册和发现&#xff0c;并以 etcd 作为简单例子简单阐述了关于服务注册和发现的应用 那么日常工作中&#xff0c;你已经使用了服务注册和发现的哪些模式呢&#xff1f; 服务注册和发现的作用 首先&#xff0c;简单说明一下服务注册和发…

大数据知识点之大数据5V特征

大数据的特征可以浓缩为五个英文单词&#xff0c;Volume(大量&#xff09;、Variety(多样性&#xff09;、Velocity(速度&#xff09;、Value(价值&#xff09;、Veracity(准确性&#xff09;。因为是5个特征都是以“V”开头的英文单词&#xff0c;又叫大数据5V特征。 概述&…

GFS文件系统

GFS 分布式文件系统 GlusterFS简介 GlusterFS 是一个开源的分布式文件系统。 由存储服务器、客户端以及NFS/Samba 存储网关&#xff08;可选&#xff0c;根据需要选择使用&#xff09;组成。 没有元数据服务器组件&#xff0c;这有助于提升整个系统的性能、可靠性和稳定性。 …

230908

1. 地址 0基础漫画式阅读&#xff1a;https://www.cnblogs.com/charlesblc/p/6130433.html 清晰详细的地址生成解释&#xff1a;比特币&#xff1a;账户私钥、公钥、地址的生成 - kumata - 博客园 (cnblogs.com) 对原理更详细解释&#xff1a;区块链技术核心篇之二&#xff…

数学建模__动态规划

动态规划就是&#xff0c;将任务每一步均记录下来&#xff0c;以便将来重复使用时能够直接调用 问题描述&#xff1a;给定n个物品&#xff0c;每个物品的重量是Wi,价值是Vi&#xff0c;但是背包最多能装下capacity重量的物品&#xff0c;问我们如何选择才能利益最大化。 这里涉…

从Endnote导入Zotero(含PDF)

概述 这个问题尚未完美的解决&#xff0c;不过本方法可行 1 在Endnote中导出.xml文件 2 替换路径 使用记事本打开导出的.xml文件 将 internal-pdf://替换为 /My EndNote Library.Data/PDF/3 在Zotero中导入 导入后可以看到有PDF附件 4 删除笔记 导入文献之后可能会有一些…

Springboot 实践(17)spring boot整合Nacos配置中心

前文我们讲解了Nacos服务端的下载安装&#xff0c;本文我们降价spring boot整合nacos&#xff0c;实现Nacos服务器配置参数的访问。 一、启动Nacos服务&#xff0c;创建三个配置文件&#xff0c;如下所示 Springboot-Nacos-Client-dev.yaml文件配置参数 Springboot-Nacos-Clie…

WebLOAD: 一站式性能测试工具

WebLOAD 是一款一站式前端性能测试工具&#xff0c;对测试人员来说使用非常方便。 它可以帮助前端工程师和测试快速对网页进行性能测试和优化&#xff0c;提高网页加载速度&#xff0c;减少页面卡顿和闪烁。 WebLOAD的特点、使用指南以及企业实际使用中的案列。 WebLOAD的特…