0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

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

DS小龙哥-嵌入式技术 2022-09-17 15:22 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

【摘要】 通过MMA7660可以做出很多项目: 比如: 老人防跌倒手环、自行车自动刹车灯,智能闹钟,烤火炉跌倒自动断电、运动手环等等。 这篇文章就介绍如何在Linux下编写MMA7660三轴加速度芯片的驱动,读取当前芯片的方向姿态,得到X,Y,Z三个轴的数据。MMA7660是IIC接口的,当前驱动就采用标准的IIC子系统编写驱动,使用字符设备框架将得到的数据上传递给应用层。

1. MMA7660芯片介绍

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

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

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

这篇文章就介绍如何在Linux下编写MMA7660三轴加速度芯片的驱动,读取当前芯片的方向姿态,得到X,Y,Z三个轴的数据。MMA7660是IIC接口的,当前驱动就采用标准的IIC子系统编写驱动,使用字符设备框架将得到的数据上传递给应用层。

image-20220108211859294image-20220108211941645

2. 硬件连线

当前使用的开发板是友善之臂Tiny4412开发板,使用三星EXYNOS4412芯片,板子本身自带了一颗MMA7660芯片,芯片的原理图如下:

image-20220108211848037image-20220108211911111

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

image-20220108212008898image-20220108212025997image-20220108212036925

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

Device Drivers  --->
	<*> Hardware Monitoring support  --->  
        <*>   Freescale MMA7660 Accelerometer   (将*号去掉,编译内核、烧写内核即可)
image-20220108212133903

3. 源代码

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

#include 
#include 
#include 
#include 
#include 
#include 
#include 

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 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

/* 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 Count

static 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");
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • Linux
    +关注

    关注

    88

    文章

    11628

    浏览量

    218003
  • 加速度传感器

    关注

    12

    文章

    491

    浏览量

    56409
  • mma7660
    +关注

    关注

    0

    文章

    3

    浏览量

    7474
收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    883M数字MEMS加速度计和温度传感器技术解析

    在电子工程领域,传感器的性能和特性对于系统设计至关重要。今天我们来详细解析一下883M数字MEMS加速度计和温度传感器的相关技术规格。
    的头像 发表于 12-09 15:47 117次阅读
    883M数字<b class='flag-5'>三</b><b class='flag-5'>轴</b>MEMS<b class='flag-5'>加速度</b>计和温度<b class='flag-5'>传感器</b>技术解析

    加速度传感器可以测量物体的垂直移动速度吗?

    。1.核心原理:加速度计测量的是什么?加速度传感器(accelerometer)的核心功能是测量“比力”,也就是物体所受的非引力的合力(如推力、拉力、阻力等)所产生
    的头像 发表于 10-31 13:09 770次阅读
    <b class='flag-5'>加速度</b><b class='flag-5'>传感器</b>可以测量物体的垂直移动<b class='flag-5'>速度</b>吗?

    mems加速度传感器都有哪些类型?这种mems加速度计各有什么利弊?

    MEMS加速度计是近年来发展起来的一种新型加速度计。它使用振动梁作为加速度传感器。振动梁由硅或石英晶体材料制成,并通过静电或压电作用以共振频率振动。双端梁以振动
    的头像 发表于 10-22 15:04 314次阅读

    【技术】如何正确理解加速度传感器频率响应特性?

    加速度传感器的各项指标中,频率响应是个非常重要的参数,它是传感器提供线性反应的频率范围。本文着重从频率响应出发带领大家更深入了解加速度传感器
    的头像 发表于 10-22 12:11 453次阅读
    【技术】如何正确理解<b class='flag-5'>加速度</b><b class='flag-5'>传感器</b>频率响应特性?

    加速度传感器需要考虑的五大因素

    在严苛和复杂的环境中研究、开发和测试产品时,加速度传感器能够提供宝贵的数据。但在某些行业,采集数据(特别是高g值下的测量)可能比较困难。因为加速度
    的头像 发表于 10-20 14:14 228次阅读
    <b class='flag-5'>加速度</b><b class='flag-5'>传感器</b>需要考虑的五大因素

    冲击加速度传感器462系列:精准捕捉极端环境下的动态冲击--森瑟科技

    在工业测试、运动学研究和爆炸冲击监测等领域,对高g值冲击加速度的精确测量至关重要。Senther推出的462系列冲击加速度传感器,凭借其
    的头像 发表于 09-22 16:22 945次阅读
    <b class='flag-5'>三</b><b class='flag-5'>轴</b>冲击<b class='flag-5'>加速度</b><b class='flag-5'>传感器</b>462系列:精准捕捉极端环境下的动态冲击--森瑟科技

    Murata加速度传感器的FAQ

    Q:加速度传感器与倾斜传感器有何区别?A:Murata的倾斜传感器加速度传感器,都以相同的ME
    的头像 发表于 09-10 12:02 586次阅读
    Murata<b class='flag-5'>加速度</b><b class='flag-5'>传感器</b>的FAQ

    如何利用加速度传感器测量频率

    在当代社会,技术的飞速发展犹如一道闪电,照亮了各行各业的发展之路。无线加速度传感器,、在众多领域中发挥着不可或缺的关键作用。在工业自动化的领域,这些
    的头像 发表于 08-04 08:45 472次阅读
    如何利用<b class='flag-5'>三</b><b class='flag-5'>轴</b><b class='flag-5'>加速度</b><b class='flag-5'>传感器</b>测量频率

    贸泽开售提供精确工业状态监测维护的 Amphenol Wilcoxon 883M数字MEMS加速度

    数字微机电系统 (MEMS) 加速度计。该高精度传感器可为状态监测维护和故障诊断提供全面的振动分析。883M MEMS加速度计专为旋转机
    的头像 发表于 07-23 16:13 1336次阅读
    贸泽开售提供精确工业状态监测维护的 Amphenol Wilcoxon 883M数字<b class='flag-5'>三</b><b class='flag-5'>轴</b>MEMS<b class='flag-5'>加速度</b>计

    加速度传感器的应用与选购技巧

    加速度传感器是一种能够测量加速力的电子设备,其核心工作原理基于牛顿的第二运动定律。当传感器感受到外部加速度时,其内部的电子器件会发生变化,进
    的头像 发表于 03-17 16:47 1096次阅读
    <b class='flag-5'>加速度</b><b class='flag-5'>传感器</b>的应用与选购技巧

    加速度传感器的工作原理和应用

    当你的手机屏幕随着手腕转动自动切换横竖屏,当智能手环精确记录下每天的步数,当汽车遭遇碰撞的瞬间安全气囊闪电般弹出——这些看似“智能”的反应,其实都源于一个指甲盖大小的装置: 加速度传感器 。它如同
    的头像 发表于 02-27 19:59 1697次阅读

    加速度传感器的选型?主要看这八大参数!

    加速度传感器作为测量物体运动状态的重要工具,被广泛应用于智能手机、可穿戴设备、汽车安全系统、航空航天等多个领域。为了确保所选加速度传感器能够满足特定应用需求,了解其关键选型参数至关重要
    的头像 发表于 01-23 18:02 2862次阅读
    <b class='flag-5'>加速度</b><b class='flag-5'>传感器</b>的选型?主要看这八大参数!

    加速度传感器的工作原理

    本文的关键要点 ・“加速度传感器”是用来检测单位时间内的速度(即加速度)的传感器。 ・从原理方面看,加速
    的头像 发表于 01-08 16:19 2148次阅读
    <b class='flag-5'>加速度</b><b class='flag-5'>传感器</b>的工作原理

    姿态传感器模块 | 集成加速度计、陀螺仪、磁力计,自带BLE5.0蓝牙

    海凌科全新推出HLK-AS2001十姿态传感器模块,集成加速度计、陀螺仪和磁力计,自带BLE5.0蓝牙,开发简单,应用广泛。什么是十姿态
    的头像 发表于 01-06 12:47 1496次阅读
    十<b class='flag-5'>轴</b>姿态<b class='flag-5'>传感器</b>模块 | 集成<b class='flag-5'>加速度</b>计、陀螺仪、磁力计,自带BLE5.0蓝牙