资讯详情

Linux驱动开发-编写MMA7660三轴加速度传感器

1. MMA7660芯片介绍

MMA7660FC 是 ± 1.5 克三轴数字输出,超低功率,紧凑型电容微电机三轴加速度计,功耗很低,容量很小MEMS 传感器。具有偏移和增益误差补偿补偿偏移和增益误差,以及用户可以将其转换为 6 位分辨率和输出速率。MMA7660芯片可以中断引脚(INT)向外通知传感器数据变化、方向、姿态识别等信息。.4V 至 3.6V,数字工作电压范围 1.71V 到 3.6V 。常用于手机、手持电脑、车载导航、便携式电脑防盗、自动自行车刹车灯、运动检测手镯、数码机、自动叫醒闹钟等。

特别是步骤计算的功能现在是最常见的,智能手镯和手机都有三轴加速度计,可以记录每天的步数,计算运动量等。现在很多不倒翁、无人机、相机云台,很多常见的产品都能看到三轴加速度计。

通过MMA7660可以做出很多项目: 比如: 老人防跌倒手环、自行车自动刹车灯,智能闹钟,烤火炉跌倒自动断电、运动手环等等。

本文介绍了如何介绍这篇文章Linux下编写MMA由7660三轴加速芯片驱动,读取当前芯片的方向和姿态,获得X,Y,Z三轴数据。MMA7660是IIC当前驱动器采用标准接口IIC使用字符设备框架将获得的数据传输到应用层的子系统编写驱动器。

image-20220108211859294

image-20220108211941645

2. 硬件连线

目前使用的开发板是友好之臂Tiny三星4412开发板EXYNOS4412芯片,板本身有一个MMA芯片原理图如下:

image-20220108211848037

image-20220108211911111

内核本身有MMA7660驱动,以下是源码路径:

image-20220108212008898

image-20220108212025997

image-20220108212036925

假如加载自己编写的驱动,还需要去掉原来内核自带的驱动,否则无法匹配。

Device Drivers  --->  <*>  Hardware Monitoring support  --->                    <*>      Freescale MMA7660 Accelerometer   (将*删除编译内核和烧写内核)

image-20220108212133903

3. 源代码

3.1 mma7660设备端代码: IIC子系统

#include  <linux/init.h>#include  <linux/module.h>#include  <linux/platform_device.h>#include  <linux/i2c.h>#include  <linux/gpio.h>#include  <mach/gpio.h>#include  <plat/gpio-cfg.h>static  struct  i2c_client *i2cClient =  NULL;static  unsigned  short    i2c_addr_list[]=  {     0x4c,  I2C_CLIENT_END};/*地址队列*//*1. 获取控制器(总线)2. 探测设备是否存在3. 定义一个名字用于找到驱动端 */static int __init mma7660_dev_init(void){
     	/*mach-tiny4412.c*/	struct i2c_adapter *i2c_adap=NULL;  /*获取到的总线存放在这个结构体*/	struct i2c_board_info i2c_info;     /*设备描述结构体,里面存放着设备的名字还有地址*/	/*1. 获取IIC控制器*/	i2c_adap = i2c_get_adapter(3);     /*要使用IIC_3号总线*/	if(!i2c_adap)	{
     		printk("获取IIC控制器信息失败!\n");		return -1;	}		memset(&i2c_info,0,sizeof(struct i2c_board_info));      	/*清空结构体*/	strlcpy(i2c_info.type,"mma7660_drv",I2C_NAME_SIZE);    /*名称的赋值*/	i2c_info.irq=EXYNOS4_GPX3(1); /*中断IO口*/	/*2. 创建IIC设备客户端*/	i2cClient = i2c_new_probed_device(i2c_adap,&i2c_info,i2c_addr_list,NULL);	if(!i2cClient)	{
     		printk("mma7660_探测地址出现错误!!\n");		return -1;	}	i2c_put_adapter(i2c_adap);/*设置模块使用计数*/		printk("mma7660_dev_init!!\n");	return 0;}static void __exit mma7660_dev_exit(void)//平台设备端的出口函数{
     	printk(" mma7660_dev_exit ok!!\n");	/*注销设备*/	i2c_unregister_device(i2cClient);	/*释放*/	i2c_release_client(i2cClient);}module_init(mma7660_dev_init);module_exit(mma7660_dev_exit);MODULE_LICENSE("GPL");

3.2 mma7660驱动端代码: IIC子系统

#include <linux/init.h>#include <linux/module.h>#include <linux/platform_device.h>#include <linux/i2c.h>#include <linux/irq.h>#include <linux/interrupt.h>#include <linux/gpio.h>#include <mach/gpio.h>#include <plat/gpio-cfg.h>#include <linux/workqueue.h>#include <linux/delay.h>/* MMA7760 Registers */#define MMA7660_XOUT 0x00 // 6-bit output value X#define MMA7660_YOUT 0x01 // 6-bit output value Y#define MMA7660_ZOUT 0x02 // 6-bit output value Z#define MMA7660_TILT 0x03 // Tilt status#define MMA7660_SRST 0x04 // Sampling Rate Status#define MMA7660_SPCNT 0x05 // Sleep Count#define MMA7660_INTSU 0x06 // Interrupt Setup#define MMA7660_MODE 0x07 // Mode#define MMA7660_SR 0x08 // Auto-Wake/Sleep and Debounce Filter#define MMA7660_PDET 0x09 // Tap Detection#define MMA7660_PD 0x0a // Tap Debounce Countstatic const struct i2c_device_id mma7660_id[] ={
     	{
     "mma7660_drv",0}, /*设备端的名字,0表示不需要私有数据*/	{
     }};static u32 mma7660_irq; /*触摸屏的中断编号*/static struct i2c_client *mma7660_client=NULL;static int	last_tilt = 0;#define __need_retry(__v) (__v & (1 << 6))#define __is_negative(__v) (__v & (1 << 5))static const char *mma7660_bafro[] = {
     	"未知", "前面", "背面"};static const char *mma7660_pola[] = {
     	"未知",	"左面", "向右",	"保留", "保留",	"向下", "向上",	"保留",};/*函数功能:读取一个字节的数据*/static int mma7660_read_tilt(struct i2c_client *client, int *tilt){
     	int val;	do {
     		val = i2c_smbus_read_byte_data(client, MMA7660_TILT);	} while (__need_retry(val));	*tilt = (val & 0xff);	return 0;}/*函数功能: 读取XYZ坐标数据*/static int mma7660_read_xyz(struct i2c_client *client, int idx, int *xyz){
     	int val;	do {
     		val = i2c_smbus_read_byte_data(client, idx + MMA7660_XOUT);	} while (__need_retry(val));	*xyz = __is_negative(val) ? (val | ~0x3f) : (val & 0x3f);	return 0;}/*工作队列处理函数*/static void mma7660_worker(struct work_struct *work){
     	int bafro, pola, shake, tap;	int val = 0;	mma7660_read_tilt(mma7660_client,&val);	/* TODO: report it ? */	bafro = val & 0x03;	if (bafro != (last_tilt & 0x03)) {
     		printk("%s\n", mma7660_bafro[bafro]);	}	pola = (val >> 2) & 0x07;	if (pola != ((last_tilt >> 2) & 0x07)) {
     		printk("%s\n", mma7660_pola[pola]);	}	shake = (val >> 5) & 0x01;	if (shake && shake != ((last_tilt >> 5) & 0x01)) {
     		printk("Shake\n");	}	tap = (val >> 7) & 0x01;	if (tap && tap != ((last_tilt >> 7) & 0x01)) {
     		printk("Tap\n");	}	/* Save current status */	last_tilt = val;		int axis[3];	int i;	for (i = 0; i < 3; i++)	{
     		mma7660_read_xyz(mma7660_client, i, &axis[i]);	}	printk("ABS_X=%d\n",axis[0]);	printk("ABS_Y=%d\n",axis[1]);	printk("ABS_Z=%d\n",axis[2]);}/*函数功能: mma7660初始化*/static int mma7660_initialize(struct i2c_client *client){
     	int val;	/* Using test mode to probe chip */	i2c_smbus_write_byte_data(client, MMA7660_MODE, 0x00);	mdelay(10);	i2c_smbus_write_byte_data(client, MMA7660_MODE, 0x04);	mdelay(10);	i2c_smbus_write_byte_data(client, MMA7660_XOUT, 0x3f);	i2c_smbus_write_byte_data(client, MMA7660_YOUT, 0x01);	i2c_smbus_write_byte_data(client, MMA7660_ZOUT, 0x15);	val = i2c_smbus_read_byte_data(client, MMA7660_ZOUT);	if (val != 0x15) {
     		dev_err(&client->dev, "no device\n");		return -ENODEV;	}	/* Goto standby mode for configuration */	i2c_smbus_write_byte_data(client, MMA7660_MODE, 0x00);	mdelay(10);	/* Sample rate: 64Hz / 16Hz; Filt: 3 samples */	i2c_smbus_write_byte_data(client, MMA7660_SR, ((2<<5) | (1<<3) | 1));	/* Sleep count */	i2c_smbus_write_byte_data(client, MMA7660_SPCNT, 0xA0);	/* Tap detect and debounce ~4ms */	i2c_smbus_write_byte_data(client, MMA7660_PDET, 4);	i2c_smbus_write_byte_data(client, MMA7660_PD, 15);	/* Enable interrupt except exiting Auto-Sleep */	i2c_smbus_write_byte_data(client, MMA7660_INTSU, 0xe7);	/* IPP, Auto-wake, auto-sleep and standby */	i2c_smbus_write_byte_data(client, MMA7660_MODE, 0x59);	mdelay(10);	/* Save current tilt status */	mma7660_read_tilt(client, &last_tilt);	mma7660_client = client;	return 0;}/*静态方式初始化工作队列*/DECLARE_WORK(mma7660_work,mma7660_worker);static irqreturn_t mma7660_interrupt(int irq, void *dev_id){
     	/*调度共享工作队列*/	schedule_work(&mma7660_work);	return IRQ_HANDLED;}/*匹配成功时调用*/static int mma7660_probe(struct i2c_client *client, const struct i2c_device_id *device_id){
     	printk("mma7660_probe!!!\n");	printk("驱动端IIC匹配的地址=0x%x\n",client->addr);		mma7660_client=client;		/*1. 注册中断*/	mma7660_irq=gpio_to_irq(client->irq);/*获取中断编号*/    if(request_irq(mma7660_irq,mma7660_interrupt,IRQF_TRIGGER_FALLING,"mma7660_irq",NULL)!=0)    {
     		printk("mma7660_中断注册失败!\n");	}		/*2. 初始化mma7660*/	if(mma7660_initialize(client) < 0)	{
     		printk(" 初始化mma7660失败!\n");	}    return 0;}static int mma7660_remove(struct i2c_client *client){
     	free_irq(mma7660_irq,NULL);	printk("mma7660_remove!!!\n");	return 0;}struct i2c_driver i2c_drv ={
     	.driver =	{
     		.name = "mma7660",		.owner = THIS_MODULE,	},		.probe = mma7660_probe,   //探测函数	.remove = mma7660_remove, //资源卸载	.id_table = mma7660_id,   //里面有一个名字的参数用来匹配设备端名字};static int __init mma7660_drv_init(void){
     	/*向iic总线注册一个驱动*/	i2c_add_driver(&i2c_drv);	return 0;}static void __exit mma7660_drv_exit(void){
     	/*从iic总线注销一个驱动*/	i2c_del_driver(&i2c_drv);}module_init(mma7660_drv_init);module_exit(mma7660_drv_exit);MODULE_LICENSE("GPL");

标签: 三轴电容加速度计断电传感器怎么安装电机刹车电容

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台