linux MCP4728 IIC 多路DAC输出芯片驱动(一)

文章介绍了在Linux环境下使用MCP4728多路DAC芯片的驱动移植过程,包括应用层通过I2C接口的读写操作,以及寄存器的读写策略和计算公式,适用于不具备内核驱动开发经验的开发者。
摘要由CSDN通过智能技术生成

背景

在项目中使用到了多路电压设置模块,之前一直使用的是ad569 四通道输出芯片,这次则使用到一个之前没有接触过的芯片MCp4728,内核中没有集成驱动,需要自己写,因此用该文档记录驱动移植的一个过车过程。

芯片手册现在地址(不需要积分):https://download.csdn.net/download/ZYH10140/88498978

该系列总共分为3篇,

第一篇讲解如何在用应用层使用iic驱动直接读写芯片mcp4728;

linux MCP4728 IIC 多路DAC输出芯片驱动(一)-CSDN博客

第二篇讲解使用字符驱动,应用层调用open、read、write等读写芯片mcp4728;

linux MCP4728 IIC 多路DAC输出芯片驱动(二)-CSDN博客

第三篇则讲解使用iiO驱动模型生成对应的文件,应用层调用cat、echo等读写芯片mcp4728;

linux MCP4728 IIC 多路DAC输出芯片驱动(三)-CSDN博客

1.应用程读写iic

I2CADDR:0x60

1.1应用程读iic封装

/********************** 
i2c读函数,
参数1:从设备地址,
参数2:寄存器地址,
参数3:读取数据缓冲区,
参数4:读取数据大小 
*************************************/ 
unsigned char _i2c_read(unsigned char device_addr, unsigned char sub_addr, unsigned char *buff, int ByteNo) 
{     
	int fd, ret;     
	unsigned char buftmp[32];     
	struct i2c_rdwr_ioctl_data i2c_data;     
 
	//----------------------------------      
	//device_addr >>= 1;     
	
	//init     
	fd = open(i2c_dev, O_RDWR);     
	if (fd<0)     
	{        
		 printf("not have /dev/i2c-1 t\r\n");         
		 return -1;     
	}  
	 
	i2c_data.nmsgs = 2;     
	i2c_data.msgs = (struct i2c_msg *)malloc(i2c_data.nmsgs *sizeof(struct i2c_msg));     
	if (i2c_data.msgs == NULL)     
	{         
		 printf("malloc error");         
		 close(fd);         
		 return -1;     
	}      
	 
	 ioctl(fd, I2C_TIMEOUT, 1);     
	 ioctl(fd, I2C_RETRIES, 2);
	 
	 //write reg     
	 memset(buftmp, 0, 32);     
	 buftmp[0] = sub_addr;     
	 i2c_data.msgs[0].len = 1;     
	 i2c_data.msgs[0].addr = device_addr;     
	 i2c_data.msgs[0].flags = 0;     // 0: write 1:read     
	 i2c_data.msgs[0].buf = buftmp;     //read data     
	 i2c_data.msgs[1].len = ByteNo;     
	 i2c_data.msgs[1].addr = device_addr;     
	 i2c_data.msgs[1].flags = 1;     // 0: write 1:read     
	 i2c_data.msgs[1].buf = buff;  
     
	 ret = ioctl(fd, I2C_RDWR, (unsigned long)&i2c_data);     
	 if (ret < 0)     
	 {         
		 printf("read data %x %x error\r\n", device_addr, sub_addr);         
		 close(fd);         
		 free(i2c_data.msgs);         
		 return 1;     
	 }     
	 
	 free(i2c_data.msgs);     
	 close(fd); 
	 
	 #if 1     
	 int i;    
	 printf("i2c__read 0x%02x:",buftmp[0]);     
	 for (i = 0; i < ByteNo; i++)     
	 {     
		printf(" 0x%02x",buff[i]);     
	 }   
	 
	 printf("\n"); 
	 #endif   
	 
	 return 0; 
 } 

1.2应用层写iic

/***************************   
 i2c写函数,
 参数1:从设备地址,
 参数2:寄存器地址,
 参数3:要写入的数据缓冲区,
 参数4:写入数据大小 
 **********************/ 
 unsigned char _i2c_write(unsigned char device_addr, unsigned char sub_addr, unsigned char *buff, int ByteNo) 
 {     
	 int fd, ret;     
	 unsigned char buftmp[32];     
	 struct i2c_rdwr_ioctl_data i2c_data;     
	 
	 //----------------------------------      
	 
	 //device_addr >>= 1;     
	 //init  
	 fd = open(i2c_dev, O_RDWR);     
	 if (fd < 0)     
	 {         
		 printf("not have /dev/i2c-1\r\n");         
		 return -1;     
	 }   
	 
	 i2c_data.nmsgs = 1;     
	 i2c_data.msgs = (struct i2c_msg *)malloc(i2c_data.nmsgs *sizeof(struct i2c_msg));     
	 if (i2c_data.msgs == NULL)     
	 {         
		 printf("malloc error");         
		 close(fd);         
		 return -1;     
	 }  
	 
	 ioctl(fd, I2C_TIMEOUT, 1);     
	 ioctl(fd, I2C_RETRIES, 2);      
	 memset(buftmp, 0, 32);     
	 buftmp[0] = sub_addr;     
	 memcpy(buftmp + 1, buff, ByteNo);   
	 
	 i2c_data.msgs[0].len = ByteNo + 1;;     
	 i2c_data.msgs[0].addr = device_addr;     
	 i2c_data.msgs[0].flags = 0;     // 0: write 1:read     
	 i2c_data.msgs[0].buf = buftmp;     
	 ret = ioctl(fd, I2C_RDWR, (unsigned long)&i2c_data);     
	 if (ret < 0)    
	 {         
		 printf("write reg %x %x error\r\n", device_addr, sub_addr);         
		 close(fd);         
		 free(i2c_data.msgs);         
		 return 1;     
	 }
     
	 free(i2c_data.msgs);     
	 close(fd); 
	 
#if 1     
	 int i;     
	 printf("i2c_write 0x%02x:",buftmp[0]);     
	 for(i=0; i<ByteNo; i++)     
	 {     
		printf(" 0x%02x",buftmp[1+i]);     
	 }  
	 
	 printf("\n"); 
#endif     

	 _alpu_delay_ms(100);
     
	 return 0; 
 }   

有了应用层操作iic的接口,那么接下来我们就直接操作芯片;

2.MCP4728寄存器读写

2.1mcp4728芯片简单讲解

下面我们主要讲解快速操作祥光部分,其他的详细讲解见《linux MCP4728 IIC 多路输出芯片驱动(二)》

根据以上藐视,可对单独的通道进行读写,具体指令分析如下:

1st byte:地址和读写状态

2nd byte: 7-3bit:固定,具体查看手册

                2-1bit:通道选择

                0bit:EEPROM同步

根据上述分析可以得到都每个通道单独的读指令:

第一字节:地址和读写标志;

第二字节:功能和通道选择等;c2 c1 c0 W1 W0固定即可;DAC1 DAC0选择通道;UDAC:0同步的吧eeprom;因此四路的读写给功能码为:0x58 0x5A;0x5C;0x5E

2.2计算公式

outV = (add * valueR)/4096;

valueR: 输入寄存器的值

outV :要输出的电压

即:输出电压和输入值的关系如下:

valueR = 1241*outV;

比如输出1.5v寄存器的值为:1241 * 1.5 = 1861

2.2分析读指令

iic_id:0x60 

以A通到为列读指令:0x60 0x58读取三字节,结合上面封装的接口:

输出:0xc0 0x07 0x45 其中0x0745 为1861; 代表为1.5v

2.3分析写指令

iic_id:0x60 

以A通到为列读指令:0x60 0x58读取三字节,结合上面封装的接口:

输出:0xc0 0x07 0x45 其中0x0745 为1861; 代表为1.5v

2.4完整代码

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <signal.h>
#include <fcntl.h>
#include <ctype.h>
#include <termios.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <linux/input.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include <sys/ioctl.h>

 
#define i2c_dev "/dev/i2c-5"    
 /****************************   延时函数(ms) *******************************************/

 void _alpu_delay_ms(unsigned int i)   
 {     
	usleep(2000 * i); 
 }
 

/********************** 
i2c读函数,
参数1:从设备地址,
参数2:寄存器地址,
参数3:读取数据缓冲区,
参数4:读取数据大小 
*************************************/ 
unsigned char _i2c_read(unsigned char device_addr, unsigned char sub_addr, unsigned char *buff, int ByteNo) 
{     
	int fd, ret;     
	unsigned char buftmp[32];     
	struct i2c_rdwr_ioctl_data i2c_data;     
 
	//----------------------------------      
	//device_addr >>= 1;     
	
	//init     
	fd = open(i2c_dev, O_RDWR);     
	if (fd<0)     
	{        
		 printf("not have /dev/i2c-1 t\r\n");         
		 return -1;     
	}  
	 
	i2c_data.nmsgs = 2;     
	i2c_data.msgs = (struct i2c_msg *)malloc(i2c_data.nmsgs *sizeof(struct i2c_msg));     
	if (i2c_data.msgs == NULL)     
	{         
		 printf("malloc error");         
		 close(fd);         
		 return -1;     
	}      
	 
	 ioctl(fd, I2C_TIMEOUT, 1);     
	 ioctl(fd, I2C_RETRIES, 2);
	 
	 //write reg     
	 memset(buftmp, 0, 32);     
	 buftmp[0] = sub_addr;     
	 i2c_data.msgs[0].len = 1;     
	 i2c_data.msgs[0].addr = device_addr;     
	 i2c_data.msgs[0].flags = 0;     // 0: write 1:read     
	 i2c_data.msgs[0].buf = buftmp;     //read data     
	 i2c_data.msgs[1].len = ByteNo;     
	 i2c_data.msgs[1].addr = device_addr;     
	 i2c_data.msgs[1].flags = 1;     // 0: write 1:read     
	 i2c_data.msgs[1].buf = buff;  
     
	 ret = ioctl(fd, I2C_RDWR, (unsigned long)&i2c_data);     
	 if (ret < 0)     
	 {         
		 printf("read data %x %x error\r\n", device_addr, sub_addr);         
		 close(fd);         
		 free(i2c_data.msgs);         
		 return 1;     
	 }     
	 
	 free(i2c_data.msgs);     
	 close(fd); 
	 
	 #if 1     
	 int i;    
	 printf("i2c__read 0x%02x:",buftmp[0]);     
	 for (i = 0; i < ByteNo; i++)     
	 {     
		printf(" 0x%02x",buff[i]);     
	 }   
	 
	 printf("\n"); 
	 #endif   
	 
	 return 0; 
 } 
 
 
 /***************************   
 i2c写函数,
 参数1:从设备地址,
 参数2:寄存器地址,
 参数3:要写入的数据缓冲区,
 参数4:写入数据大小 
 **********************/ 
 unsigned char _i2c_write(unsigned char device_addr, unsigned char sub_addr, unsigned char *buff, int ByteNo) 
 {     
	 int fd, ret;     
	 unsigned char buftmp[32];     
	 struct i2c_rdwr_ioctl_data i2c_data;     
	 
	 //----------------------------------      
	 
	 //device_addr >>= 1;     
	 //init  
	 fd = open(i2c_dev, O_RDWR);     
	 if (fd < 0)     
	 {         
		 printf("not have /dev/i2c-1\r\n");         
		 return -1;     
	 }   
	 
	 i2c_data.nmsgs = 1;     
	 i2c_data.msgs = (struct i2c_msg *)malloc(i2c_data.nmsgs *sizeof(struct i2c_msg));     
	 if (i2c_data.msgs == NULL)     
	 {         
		 printf("malloc error");         
		 close(fd);         
		 return -1;     
	 }  
	 
	 ioctl(fd, I2C_TIMEOUT, 1);     
	 ioctl(fd, I2C_RETRIES, 2);      
	 memset(buftmp, 0, 32);     
	 buftmp[0] = sub_addr;     
	 memcpy(buftmp + 1, buff, ByteNo);   
	 
	 i2c_data.msgs[0].len = ByteNo + 1;;     
	 i2c_data.msgs[0].addr = device_addr;     
	 i2c_data.msgs[0].flags = 0;     // 0: write 1:read     
	 i2c_data.msgs[0].buf = buftmp;     
	 ret = ioctl(fd, I2C_RDWR, (unsigned long)&i2c_data);     
	 if (ret < 0)    
	 {         
		 printf("write reg %x %x error\r\n", device_addr, sub_addr);         
		 close(fd);         
		 free(i2c_data.msgs);         
		 return 1;     
	 }
     
	 free(i2c_data.msgs);     
	 close(fd); 
	 
#if 1     
	 int i;     
	 printf("i2c_write 0x%02x:",buftmp[0]);     
	 for(i=0; i<ByteNo; i++)     
	 {     
		printf(" 0x%02x",buftmp[1+i]);     
	 }  
	 
	 printf("\n"); 
#endif     

	 _alpu_delay_ms(100);
     
	 return 0; 
 }   

 
int main()
{
 
 	unsigned char buff[512] = {0x00, 0x01, 0x02};
	_i2c_read(0x60, 0x58, buff, 3) ;
	_i2c_read(0x60, 0x5A, buff, 3) ;
    _i2c_read(0x60, 0x5C, buff, 3) ;
    _i2c_read(0x60, 0x5E, buff, 3) ;
	_alpu_delay_ms(100);
	
    buff[0] = 0x07;
    buff[1] = 0x45;
	_i2c_write(0x60, 0x58, buff, 2) ;
    _i2c_write(0x60, 0x5A, buff, 2) ;
    _i2c_write(0x60, 0x5C, buff, 2) ;
    _i2c_write(0x60, 0x5E, buff, 2) ;
	_alpu_delay_ms(100);
    _i2c_read(0x60, 0x5E, buff, 3) ;

	return 0;
}

3.总结

该方法能够快速实现功能,不需要掌握能内核、驱动等开发技能。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值