【摘要】 通過MMA7660可以做出很多項目: 比如: 老人防跌倒手環(huán),、自行車自動剎車燈,智能鬧鐘,,烤火爐跌倒自動斷電,、運動手環(huán)等等,。 這篇文章就介紹如何在Linux下編寫MMA7660三軸加速度芯片的驅(qū)動,讀取當前芯片的方向姿態(tài),,得到X,Y,Z三個軸的數(shù)據(jù),。MMA7660是IIC接口的,當前驅(qū)動就采用標準的IIC子系統(tǒng)編寫驅(qū)動,,使用字符設備框架將得到的數(shù)據(jù)上傳遞給應用層,。
1. MMA7660芯片介紹
MMA7660FC 是 ± 1.5 克的三軸數(shù)字輸出、超低功率,、緊湊型電容式微電機的三軸加速度計,,是非常低功耗,小型容性 MEMS 的傳感器,。具有低通濾波器,,用于偏移和增益誤差補償, 以及用戶可配置的轉(zhuǎn)換成 6 位分辨率,,用戶可配置輸出速率等功能,。MMA7660芯片可以通過中斷引腳(INT)向外通知傳感器數(shù)據(jù)變化,、方向、姿態(tài)識別等信息,。模擬工作電壓范圍是 2.4V 至 3.6V,,數(shù)字工作電壓范圍是 1.71V 到 3.6V 。常用在手機,、掌上電腦,、車載導航,便攜式電腦的防盜,,自動自行車剎車燈,、運動檢測手環(huán)、數(shù)碼機,、自動叫醒鬧鐘里等等,。
特別是計步的功能是現(xiàn)在最常見,不管是智能手環(huán),、還是手機都帶有三軸加速度計,,可以記錄每天的步數(shù),計算運動量等?,F(xiàn)在很多的不倒翁,,無人機、相機云臺,,很多常見的產(chǎn)品里都能看到三軸加速計的身影,。
通過MMA7660可以做出很多項目: 比如: 老人防跌倒手環(huán)、自行車自動剎車燈,,智能鬧鐘,,烤火爐跌倒自動斷電、運動手環(huán)等等,。
這篇文章就介紹如何在Linux下編寫MMA7660三軸加速度芯片的驅(qū)動,,讀取當前芯片的方向姿態(tài),得到X,Y,Z三個軸的數(shù)據(jù),。MMA7660是IIC接口的,,當前驅(qū)動就采用標準的IIC子系統(tǒng)編寫驅(qū)動,使用字符設備框架將得到的數(shù)據(jù)上傳遞給應用層,。
2. 硬件連線
當前使用的開發(fā)板是友善之臂Tiny4412開發(fā)板,,使用三星EXYNOS4412芯片,板子本身自帶了一顆MMA7660芯片,,芯片的原理圖如下:
內(nèi)核本身有MMA7660的驅(qū)動,,下面是源碼的路徑:
如果加載自己編寫的驅(qū)動,還需要去掉原來內(nèi)核自帶的驅(qū)動,不然無法匹配,。
Device Drivers --->
<*> Hardware Monitoring support --->
<*> Freescale MMA7660 Accelerometer (將*號去掉,,編譯內(nèi)核、燒寫內(nèi)核即可)
3. 源代碼
3.1 mma7660設備端代碼: IIC子系統(tǒng)
#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. 定義一個名字用于找到驅(qū)動端
*/
static int __init mma7660_dev_init(void)
{
/*mach-tiny4412.c*/
struct i2c_adapter *i2c_adap=NULL; /*獲取到的總線存放在這個結(jié)構(gòu)體*/
struct i2c_board_info i2c_info; /*設備描述結(jié)構(gòu)體,,里面存放著設備的名字還有地址*/
/*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)),; /*清空結(jié)構(gòu)體*/
strlcpy(i2c_info.type,“mma7660_drv”,,I2C_NAME_SIZE); /*名稱的賦值*/
i2c_info.irq=EXYNOS4_GPX3(1),; /*中斷IO口*/
/*2. 創(chuàng)建IIC設備客戶端*/
i2cClient = i2c_new_probed_device(i2c_adap,&i2c_info,i2c_addr_list,NULL),;
if(!i2cClient)
{
printk(“mma7660_探測地址出現(xiàn)錯誤??!\n”);
return -1;
}
i2c_put_adapter(i2c_adap),;/*設置模塊使用計數(shù)*/
printk(“mma7660_dev_init!!\n”),;
return 0;
}
static void __exit mma7660_dev_exit(void)//平臺設備端的出口函數(shù)
{
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驅(qū)動端代碼: IIC子系統(tǒng)
復制
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
/* MMA7760 Registers */
#define MMA7660_XOUT0x00// 6-bit output value X
#define MMA7660_YOUT0x01// 6-bit output value Y
#define MMA7660_ZOUT0x02// 6-bit output value Z
#define MMA7660_TILT0x03// Tilt status
#define MMA7660_SRST0x04// Sampling Rate Status
#define MMA7660_SPCNT0x05// Sleep Count
#define MMA7660_INTSU0x06// Interrupt Setup
#define MMA7660_MODE0x07// Mode
#define MMA7660_SR0x08// Auto-Wake/Sleep and Debounce Filter
#define MMA7660_PDET0x09// Tap Detection
#define MMA7660_PD0x0a// Tap Debounce Count
static const struct i2c_device_id mma7660_id[] =
{
{“mma7660_drv”,,0}, /*設備端的名字,,0表示不需要私有數(shù)據(jù)*/
{}
};
static u32 mma7660_irq; /*觸摸屏的中斷編號*/
static struct i2c_client *mma7660_client=NULL;
static intlast_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[] = {
“未知”,,
“左面”, “向右”,,
“保留”,, “保留”,
“向下”,, “向上”,,
“保留”,
};
/*
函數(shù)功能:讀取一個字節(jié)的數(shù)據(jù)
*/
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;
}
/*
函數(shù)功能: 讀取XYZ坐標數(shù)據(jù)
*/
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;
}
/*
工作隊列處理函數(shù)
*/
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]),;
}
/*
函數(shù)功能: 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;
}
/*
靜態(tài)方式初始化工作隊列
*/
DECLARE_WORK(mma7660_work,mma7660_worker);
static irqreturn_t mma7660_interrupt(int irq, void *dev_id)
{
/*調(diào)度共享工作隊列*/
schedule_work(&mma7660_work);
return IRQ_HANDLED;
}
/*
匹配成功時調(diào)用
*/
static int mma7660_probe(struct i2c_client *client, const struct i2c_device_id *device_id)
{
printk(“mma7660_probe!!!\n”),;
printk(“驅(qū)動端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, //探測函數(shù)
.remove = mma7660_remove, //資源卸載
.id_table = mma7660_id, //里面有一個名字的參數(shù)用來匹配設備端名字
};
static int __init mma7660_drv_init(void)
{
/*向iic總線注冊一個驅(qū)動*/
i2c_add_driver(&i2c_drv),;
return 0;
}
static void __exit mma7660_drv_exit(void)
{
/*從iic總線注銷一個驅(qū)動*/
i2c_del_driver(&i2c_drv),;
}
module_init(mma7660_drv_init);
module_exit(mma7660_drv_exit),;
MODULE_LICENSE(“GPL”),;
更多信息可以來這里獲取==>>電子技術(shù)應用-AET<<