mcp4725是一款低功耗,高精度 单通道,拥有EEPROM的12位的dac。

由于最近项目中使用到了该芯片所以贴出来给大家参考(步进电机电机芯片半流锁定。)

本贴呢非项目中使用的平台,主要是想在linux 下实现对该器件的使用,实现一个简单的i2c dac字符驱动。

对于i2c 基本原理通信协议呢不做过多描述。

1.mcp4725 地址

mcp4725官方默认地址是一般是b'1100 (96) a0 可通过外部上拉或者下拉决定。

 

2.数据流程

 

通过前面图可以看到mcp4725 控制起来是非常简单的 第一个字节主要是器件地址(7位)+读写位(1位)。第二个字节 高4位呢是控制指令,低4位呢主要配合后面的第三个字节,是第三个字节的高4位。

那么快速模式怎么使用呢?比如需要2v 电压。

假设VDD 为电源电压5V dac的压降为0.7v 那么 我们需要2v 的的电压 Vout=2/(5-0.7)*4095=1905 ,转换为2进制可以看到

 

高4位位0111 低7位为01110001  。那么对应给设备发送 就应当为 (16进制):0x60  0x07 0x71 那么我们的数据就写好了。

本环境在MT7628 openWRT 环境下,MT7628  只有1个i2c 总线接口他的地址为0x10000900

由于linux 使用设备树,其设备树定义为:

 

下面看一下linux 驱动代码的具体实现:

#include <linux/i2c.h>
#include <linux/of.h>
#include <linux/mod_devicetable.h>
#include <linux/device.h>
#include <linux/slab.h>
#include <linux/cdev.h>
#include <linux/fs.h>

int major;
struct class *cls;
struct mcp4725_dev_t
{
	struct cdev chrdev;
	struct device *device;
	struct i2c_client *cli;
	int index;
};


int mcp4725_open(struct inode *inode,struct file *file)
{
   struct mcp4725_dev_t *pri=container_of(inode->i_cdev,struct mcp4725_dev_t,chrdev);//container_of(inode->i_cdev,struct mcp4725_dev_t,chardev);
   struct i2c_client *cli;
   file->private_data=pri;
   cli=pri->cli;
  
    printk("%s->%d\n",__func__,__LINE__);
	return 0;
}

int mcp4725_close(struct inode *inode,struct file *file)
{
    printk("%s->%d\n",__func__,__LINE__);
	return 0;
}

long mcp4725_ioctl(struct file * file, unsigned int cmd, unsigned long args)
{
	printk("%s->%d\n",__func__,__LINE__);
 	return 0;
}

int mcp_write(struct i2c_client *cli,unsigned short val)
{
	int ret=0;
	unsigned char buf[2];
	struct i2c_msg msg;
	buf[0]=(unsigned char)(val>>8);//高位4位
	buf[1]=(unsigned char)val;//低8位
	msg.addr=cli->addr;
	msg.buf=buf;
	msg.flags=0;
	//msg.
	msg.len=2;
	ret=i2c_transfer(cli->adapter,&msg,1);
	if(ret!=1)
	{
		printk("%s->%d i2c_transfer ret%d\n",__func__,__LINE__,ret);
		return -23;
	}
    printk("send %daddr:%d->%d\n",__LINE__,cli->addr,val);
	return 0;
}

int mcp4725_write(struct file *file, const char __user *usr, size_t size, loff_t *loff)
{

    int ret=0;
	unsigned short user_data;
    struct i2c_client *cli=NULL;
	struct mcp4725_dev_t *pri=file->private_data;
	cli=pri->cli;
	//char buf
	
    ret = copy_from_user(&user_data,usr,size);
	printk("addr:%d->%d\n",cli->addr,user_data);
	if(ret<0)
	{
		printk("error:%s->%d\n",__func__,__LINE__);
		return -20;
	}

    mcp_write(cli,user_data);

	printk("%s->%d\n",__func__,__LINE__);
	return 0;
}

struct file_operations fops_mcp4725={
	.open=mcp4725_open,
	.release=mcp4725_close,
	.write=mcp4725_write,
	.unlocked_ioctl=mcp4725_ioctl,
};


int mcp4725_remove(struct i2c_client *cli)
{
	/* data */
	return 0;
}

struct i2c_device_id id_table[] = {
};

int mcp4725_proble(struct i2c_client *cli,const struct i2c_device_id *id)
{
	int ret=0;
	struct  device_node *of_node=cli->dev.of_node;
	struct mcp4725_dev_t *mcp4725_pri=NULL;

	mcp4725_pri=kmalloc(sizeof(*mcp4725_pri),GFP_KERNEL);

    printk("addr:%d->%d\n",cli->addr,__LINE__);
	printk("%s->%d\n",__func__,__LINE__);
	memset(mcp4725_pri,0,sizeof(*mcp4725_pri));

    cli->dev.platform_data=mcp4725_pri;
	
    mcp4725_pri->cli=cli;
	

    // ret=of_property_read_u32(of_node,"index",&mcp4725_pri->index);
	// if(ret<0)
	// {
    //      printk("error:%s->%d\n",__func__,__LINE__);
	// 	return -20;
	// }
	mcp4725_pri->index=5;
	printk("%s->%d\n",__func__,__LINE__);

	cdev_init(&mcp4725_pri->chrdev,&fops_mcp4725);
	ret=cdev_add(&mcp4725_pri->chrdev,MKDEV(major,mcp4725_pri->index),1);
	if(ret<0)
	{
	    printk("error:%s->%d\n",__func__,__LINE__);
		return -21;	
	}
    
	mcp4725_pri->device=device_create(cls,NULL,MKDEV(major,mcp4725_pri->index),
	             NULL,"mcp4725xx%d",mcp4725_pri->index);
    

	if(mcp4725_pri->device==NULL)
	{
		 printk("error:%s->%d\n",__func__,__LINE__);
		return -22;	
	}
	//mcp4725_pri->device->

	printk("%s->%d\n",__func__,__LINE__);

	return 0;
}

struct of_device_id of_match_table[]={
	{.compatible="MCP4725",},
	{}
};

struct i2c_driver  i2c_mcp4725={
	.driver={
		.name="i2c_MCP4725",
		.of_match_table=of_match_table,
	},
	.id_table=id_table,
	.probe=mcp4725_proble,
	.remove=mcp4725_remove,
} ;

 int __init mcp4725_init(void)
{
    int ret=0;
	int devno;

    //alloc_chrdev_region
	ret=alloc_chrdev_region(&devno,0,255,"mcp4725 for chardev");
	if(ret<0)
	{
	    printk("%s-->%d",__func__,__LINE__);
		return -20;
	}

	major=MAJOR(devno);
	cls=class_create(THIS_MODULE,"pdev char class");
	if(!cls)
	{
	    printk("%s-->%d",__func__,__LINE__);
		return -20;
	}

   ret=i2c_add_driver(&i2c_mcp4725);
   if(ret<0)
   {
	   printk("%s-->%d",__func__,__LINE__);
	   return -20;
   }
    printk("%s-->%d",__func__,__LINE__);
	   return 0;
}
 void __exit mcp4725_exit(void)
{

    i2c_del_driver(&i2c_mcp4725);
	class_destroy(cls);
	//unregister_chrdev_region
	unregister_chrdev_region(MKDEV(major,0),255);

	printk("%s->%d",__func__,__LINE__);
	return ;
}

module_init(mcp4725_init);
module_exit(mcp4725_exit);
MODULE_LICENSE("GPL");

测试APP 为:

#include "stdio.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>


int main(int argc,char** argv)
{
    char led1=0;
    char buf[10];
    int data;
    int fd=open("/dev/mcp4725xx5",O_WRONLY);
    if(fd<0)
    {
        printf("open error \r\n");
        return  -1;
    }
    data=atoi(argv[1]);
    unsigned short val=(short)(data)/4.7*4095;
    printf("clc:%d\r\n",val);
    write(fd,&val,sizeof(short));
    printf("exit\r\n");
    close(fd);
return 1;
}

 

 

 

Logo

更多推荐