DAC MCP4725 i2c 驱动(linux)
mcp4725是一款低功耗,高精度 单通道,拥有EEPROM的12位的dac。由于最近项目中使用到了该芯片所以贴出来给大家参考(步进电机电机芯片半流锁定。)本贴呢非项目中使用的平台,主要是想在linux 下实现对该器件的使用,实现一个简单的i2c dac字符驱动。对于i2c 基本原理通信协议呢不做过多描述。1.mcp4725 地址mcp4725官方默认地址是一般是b'110...
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;
}
更多推荐
所有评论(0)