目录
一、相关驱动开发
二、A9主框架
三、脚本及数据上传实验
https://www.yuque.com/uh1h8r/dqrma0/tx0fq08mw1ar1sor?singleDoc# 《常见问题》
上个笔记的相关问题
一、相关驱动开发
/* mpu6050六轴传感器 */
i2c@138B0000 {
/* #address-cells = <1>;
#size-cells = <0>;
samsung,i2c-sda-delay = <100>;
samsung,i2c-max-bus-freq = <20000>;*/pinctrl-0 = <&i2c5_bus>;
pinctrl-names = "default";
status = "okay";
mpu6050@0x68{
compatible = "invensense,mpu6050";
reg = <0x68>;
};
};
LED和蜂鸣器没用设备树直接操作的寄存器
驱动主要就是这四个
buildmodule.sh是一个编译加拷贝的脚本
#!/bin/bash
echo "*****************************************************"
echo "just to compile the module int the current directory!"
echo "*****************************************************"echo $PWD
for file in $PWD/*
do
if [ -d "$file" ]
then
echo "$file is directory"
cd $file
make clean
make
cp *.ko *_test ../
make clean
cd -
elif [ -f "$file" ]
then
echo "$file is file"
fi
doneecho "*******************************************************"
echo "*********** compile the module over! *****************"
echo "*Do you want to mv to the file system directory y/n?*"
echo "*******************************************************"read yourchoice
case $yourchoice in
"y"|"yes"|"Y"|"YES")
echo "moving,wait a moment,please"
sleep 1
sudo mv *.ko *_test ~/nfs_rootfs/drv/
echo "moved,you are lazy,haha!"
;;
"n"|"no"|"N"|"NO")
echo "maybe you need to copy it by hand."
;;
*)
echo "I get $var,maybe your input is wrong !"
echo "There is no chance,you need to do it manually !"
;;
esac
# --- end of case ---""""""""""
每个文件夹下都是对应的驱动程序,通过配套的MAkefile来编译
这是adc的驱动
#include <linux/module.h>
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
#include <linux/fs.h>
#include <linux/wait.h>
#include <linux/sched.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <linux/of.h>
#include <linux/device.h>
static wait_queue_head_t wq;
unsigned int major = 0;
struct class *cls = NULL;
struct device *dev = NULL;
static int have_data = 0;
static int fs4412_adc;
static struct resource *res1;
static struct resource *res2;
static void *fs4412_adc_base;
#define ADCCON 0x0000
#define ADCDLY 0x0008
#define ADCDAT 0x000C
#define CLRINTADC 0x0018
#define ADCMUX 0x001C
int flags = 1;
//#define flags 1
#define DEBUG_PRINTK(msg,DEBUG_FLAG) \
do{ \
if(!!DEBUG_FLAG) { \
printk("---->%s--->%d\n",__func__,__LINE__);\
printk(msg);\
}\
}while(0)
static irqreturn_t fs4412_adc_handler(int irqno, void *dev)
{
have_data = 1; //��������
printk("--->%s--->%d.\n",__func__,__LINE__);
/*���ж�*/
writel(0x12,fs4412_adc_base + CLRINTADC);
wake_up_interruptible(&wq);
return IRQ_HANDLED;
}
static int fs4412_adc_open (struct inode *inod, struct file *filep)
{
DEBUG_PRINTK("fs4412_adc_open",flags);
return 0;
}
static ssize_t fs4412_adc_read(struct file *filep, char __user *buf, size_t len, loff_t *pos)
{
writel(0x3,fs4412_adc_base + ADCMUX);
writel(1<<0 | 1<<14 | 0X1<<16 | 0XFF<<6 ,fs4412_adc_base + ADCCON );
wait_event_interruptible(wq, have_data == 1);
/*read data ������& 0xfff,�������ݳ��� */
fs4412_adc = readl(fs4412_adc_base+ADCDAT) & 0xfff;
//�����㲻�������㣬�ӽ����ݿ�����Ӧ�ò�
if(copy_to_user(buf,&fs4412_adc,sizeof(int)))
return -EFAULT;
have_data = 0;
return len;
}
static int fs4412_adc_release(struct inode *inode, struct file *filep)
{
DEBUG_PRINTK("fs4412_adc_release",flags);
return 0;
}
static struct file_operations fs4412_adc_ops ={
.open = fs4412_adc_open,
.release = fs4412_adc_release,
.read = fs4412_adc_read,
};
static int fs4412_adc_probe(struct platform_device *pdev)
{
printk("--->%s--->%d.\n",__func__,__LINE__);
res1 = platform_get_resource(pdev,IORESOURCE_IRQ, 0);
res2 = platform_get_resource(pdev,IORESOURCE_MEM, 0);
fs4412_adc_base = ioremap(res2->start,res2->end - res2->start);
printk("res2->start,res2->end - res2->start :%#x.\n",res2->end - res2->start);
request_irq(res1->start,fs4412_adc_handler,IRQF_DISABLED,"adc1",NULL);
printk("res1->start :%d.\n",res1->start);
major = register_chrdev(0, "adc", &fs4412_adc_ops);
if(major <= 0){
printk("register_chrdev failed.\n");
return -1;
}
printk(KERN_INFO "major :%d.\n",major);
cls = class_create(THIS_MODULE, "myadc");
if(cls == NULL){
printk("class_create failed");
return -1;
}
dev = device_create(cls, NULL, MKDEV(major, 0),NULL, "fsadc%d",0);
if(dev == NULL){
printk("device_create failed.\n");
return -1;
}
init_waitqueue_head(&wq);
return 0;
}
static int fs4412_adc_remove(struct platform_device *pdev)
{
free_irq(res1->start,NULL);
free_irq(res2->start,NULL);
unregister_chrdev( major, "adc");
return 0;
}
static struct of_device_id myof_match_table[]= {
{.compatible = "fs4412,adc" },
};
static struct platform_driver fs4412_adc_driver= {
.probe = fs4412_adc_probe,
.remove = fs4412_adc_remove,
.driver ={
.name = "adc_demo",
.of_match_table = of_match_ptr(myof_match_table),
},
};
static int fs4412_adc_init(void)
{
printk("--->%s--->%d.\n",__func__,__LINE__);
return platform_driver_register(&fs4412_adc_driver);
}
static void fs4412_adc_exit(void)
{
//printk("--->%s--->%d.\n",__func__,__LINE__);
platform_driver_unregister(&fs4412_adc_driver);
return;
}
MODULE_LICENSE("GPL");
module_init(fs4412_adc_init);
module_exit(fs4412_adc_exit);
这是蜂鸣器驱动
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/io.h>
#include <asm/uaccess.h>
#include <asm/ioctl.h>
unsigned int major = 0;
const char * modulename="pwmbeeper";
dev_t devnum = 0;
struct class *cls = NULL;
struct device *dev = NULL;
#define GPD0CON 0x114000a0
#define TIMER_BASE 0x139D0000
#define TCFG0 0x0000
#define TCFG1 0x0004
#define TCON 0x0008
#define TCNTB0 0x000C
#define TCMPB0 0x0010
static unsigned int *gpd0con;
static void *timer_base;
typedef struct beep_desc{
int beep; //2 3 4 5
int beep_state; //0 or 1
int tcnt; //占空比
int tcmp; //调节占空比
}beep_desc_t;
#define mytype 'f'
#define BEEP_ON _IOW(mytype,0,beep_desc_t)
#define BEEP_OFF _IOW(mytype,1,beep_desc_t)
#define BEEP_FREQ _IOW(mytype,2,beep_desc_t)
char kbuf[] = {'1','2','3','4'};
void fs4412_beep_on(void)
{
writel (readl(timer_base +TCON ) | (0x1 <<0),timer_base +TCON );
}
void fs4412_beep_off(void)
{
writel (readl(timer_base +TCON ) | (~(1 << 0)),timer_base +TCON );
}
static void beep_freq(int beep_tcnt,int beep_tcmp)
{
//tcnt决定了周期 tcnt 取值范围:
writel (beep_tcnt, timer_base +TCNTB0 ); //计数值 100次
//tcmp设置占空比 50 / 100 = 50% 综述:占空比 = tcmp / tcnt; //决定声音的大小
writel (beep_tcmp, timer_base +TCMPB0 ); //比较值 50次
}
int demo_open(struct inode *inode, struct file *filp)
{
printk("--->%s--->%d.\n",__FUNCTION__,__LINE__);
//fs4412_beep_on();
return 0;
}
int demo_release(struct inode *inode, struct file *filp)
{
printk("--->%s--->%d.\n",__FUNCTION__,__LINE__);
fs4412_beep_off();
return 0;
}
ssize_t demo_read(struct file *filp, char __user *usrbuf, size_t size, loff_t *offset)
{
int bytes = 0;
printk("---->%s--->%d\n",__func__,__LINE__);
bytes = copy_to_user(usrbuf,kbuf,4);
if(bytes > 0){
printk("copy_to_user failed!\n");
}
return 0;
}
ssize_t demo_write (struct file *filp, const char __user *usrbuf, size_t size, loff_t *offset)
{
int bytes = 0;
printk("---->%s--->%d\n",__func__,__LINE__);
bytes = copy_from_user(kbuf,usrbuf,4);
if(bytes > 0){
printk("copy_from_user failed\n");
return -1;
}
printk("copy_from_user usrbuf:%c\n",kbuf[0]);
return 0;
}
long demo_ioctl(struct file *filp, unsigned int cmd, unsigned long args)
{
beep_desc_t *beeper = (beep_desc_t *)args;
printk("---->%s--->%d\n",__func__,__LINE__);
switch(cmd)
{
case BEEP_ON:
fs4412_beep_on();
break;
case BEEP_OFF:
fs4412_beep_off();
break;
case BEEP_FREQ:
beep_freq(beeper->tcnt,beeper->tcmp);
break;
default :
return -EINVAL;
}
return 0;
}
const struct file_operations fops={
.open = demo_open,
.read = demo_read,
.write = demo_write,
.unlocked_ioctl = demo_ioctl,
.release = demo_release,
};
void fs4412_beep_init(void)
{
gpd0con = ioremap(GPD0CON,4);
timer_base = ioremap(TIMER_BASE,4);
//一级分频:PCLK/(249 + 1) = 100MHZ/250 = 400000
//PWM.TCFG0 = 199;
writel ((readl(gpd0con)&~(0xf<<0)) | (0x2<<0),gpd0con); // GPD0_0 : TOUT_0
writel ((readl(timer_base +TCFG0 )&~(0xff<<0)) | (0Xf9 <<0),timer_base +TCFG0); //设置默认值0XF9 = 249分频
writel ((readl(timer_base +TCFG1 )&~(0xf<<0)) | (0x2<<0),timer_base +TCFG1 ); //4分频
//调整后的PWM波形 100000 / (tcnt)100 = 1000hz (20 - 20000)hz 周期1ms //设置频率 -声音的高低
//tcnt决定了周期 tcnt 取值范围:
writel (100, timer_base +TCNTB0 ); //计数值 100次
//tcmp设置占空比 50 / 100 = 50% 综述:占空比 = tcmp / tcnt; //决定声音的大小
writel (80, timer_base +TCMPB0 ); //比较值 50次
writel (readl(timer_base +TCON ) | (0x1 <<3),timer_base +TCON ); //设置自动重装载
writel (readl(timer_base +TCON ) | (0x1 <<1),timer_base +TCON ); //设置手动重装
writel (readl(timer_base +TCON ) & (~(1 << 1)),timer_base +TCON );//清除手动记载
}
static int __init demo_init(void)
{
printk("--->%s--->%d.\n",__FUNCTION__,__LINE__);
major = register_chrdev(0, modulename, &fops);
if(major <= 0){
printk("register_chrdev failed.\n");
return -1;
}
devnum = MKDEV(major, 0);
printk(KERN_INFO "major :%d.\n",major);
cls = class_create(THIS_MODULE, "fsbeeper");
if(cls == NULL){
printk("class_create failed");
return -1;
}
dev = device_create(cls, NULL, devnum,NULL, "fsbeeper%d",0);
if(dev == NULL){
printk("device_create failed.\n");
return -1;
}
fs4412_beep_init();
return 0;
}
void fs4412_beep_unioremap(void)
{
iounmap(gpd0con);
iounmap(timer_base);
}
static void __exit demo_exit(void)
{
printk("--->%s--->%d.\n",__FUNCTION__,__LINE__);
fs4412_beep_unioremap();
device_destroy(cls,devnum);
class_destroy(cls);
unregister_chrdev(major, modulename);
}
module_init(demo_init);
module_exit(demo_exit);
MODULE_LICENSE("GPL");
这是LED驱动
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <asm/uaccess.h>
#include <linux/device.h>
#include <linux/io.h>
#include "chrdev.h"
unsigned int major = 0; //动态加载
//unsigned int major = 500;
const char * name = "demoname";
char kbuf[4] = {1,2,3,4};
int numlen = ARRAY_SIZE(kbuf);
struct class * cls;
struct device * dev;
#define GPX2CON 0x11000C40
#define GPX2_7DAT 0x11000c44
#define GPX1CON 0x11000c20
#define GPX1DAT 0x11000c24
#define GPF3CON 0x114001e0
#define GPF3DAT 0x114001e4
void __iomem * gpx2con_vir;
void __iomem * gpx2dat_vir;
void __iomem * gpx1con_vir;
void __iomem * gpx1dat_vir;
void __iomem * gpf3con_vir;
void __iomem * gpf3dat_vir;
int demo_open(struct inode *inode, struct file *filp)
{
printk("-----%s-----%d.\n",__FUNCTION__,__LINE__);
return 0;
}
int demo_close(struct inode *inode, struct file *filp)
{
printk("-----%s-----%d.\n",__FUNCTION__,__LINE__);
return 0;
}
ssize_t demo_read(struct file *filp, char __user * usrbuf, size_t size, loff_t *offset)
{
int rbytes;
printk("-----%s-----%d.\n",__FUNCTION__,__LINE__);
rbytes = copy_to_user(usrbuf, kbuf, 4);
if(rbytes > 0){
printk("copy failed bytes :%d.\n",rbytes);
}
printk("copy success bytes :%d.\n",rbytes);
return 0;
}
ssize_t demo_write(struct file *filp, const char __user *usrbuf, size_t size, loff_t *offset)
{
int i = 0;
int wbytes ;
printk("-----%s-----%d.\n",__FUNCTION__,__LINE__);
wbytes = copy_from_user(kbuf, usrbuf,4);
if(wbytes > 0){
printk("copy failed bytes :%d.\n",wbytes);
}
for(i = 0;i < 4;i ++){
printk("buf[%d] :%d.\n",i,kbuf[i]);
}
printk("copy success bytes :%d.\n",wbytes);
return 0;
}
long demo_ioctl(struct file *filp, unsigned int cmd, unsigned long args)
{
int lednum = 0;
led_desc_t *led = (led_desc_t *)args;
printk("-----%s-----%d.\n",__FUNCTION__,__LINE__);
switch (cmd){
case FSLEDON:
lednum = led->which;
if(lednum == 2){
printk("fsled %d on.\n",lednum);
writel((readl(gpx2dat_vir) | 0x1 << 7),gpx2dat_vir);
//控制硬件
}else if(lednum == 3){
writel(readl(gpx1dat_vir) | (0x1 << 0),gpx1dat_vir);
printk("fsled %d on.\n",lednum);
}else if(lednum == 4){
writel(readl(gpf3dat_vir) | (0x1 << 4),gpf3dat_vir);
printk("fsled %d on.\n",lednum);
}else if(lednum == 5){
writel(readl(gpf3dat_vir) | (0x1 << 5),gpf3dat_vir);
printk("fsled %d on.\n",lednum);
}
break;
case FSLEDOFF:
lednum = led->which;
if(lednum == 2){
writel((readl(gpx2dat_vir) & ~(0x1 << 7)),gpx2dat_vir);
printk("fsled %d off.\n",lednum);
}else if(lednum == 3){
writel(readl(gpx1dat_vir)&~(0x1 << 0),gpx1dat_vir);
printk("fsled %d off.\n",lednum);
}else if(lednum == 4){
writel(readl(gpf3dat_vir)&~(0x1 << 4),gpf3dat_vir);
printk("fsled %d off.\n",lednum);
}else if(lednum == 5){
writel(readl(gpf3dat_vir)&~(0x1 << 5),gpf3dat_vir);
printk("fsled %d off.\n",lednum);
}
break;
default:
printk("default :....\n");
break;
}
return 0;
}
const struct file_operations fops = {
.open = demo_open,
.release = demo_close,
.read = demo_read,
.write = demo_write,
.unlocked_ioctl = demo_ioctl,
};
void gpio_led_ioremap(void)
{
gpx2con_vir = ioremap(GPX2CON, 4);
gpx2dat_vir = gpx2con_vir +4;
gpx1con_vir = ioremap(GPX1CON,4);
gpx1dat_vir = gpx1con_vir + 4;
gpf3con_vir = ioremap(GPF3CON,4);
gpf3dat_vir = gpf3con_vir + 4;
writel((readl(gpx2dat_vir) | 0x0 << 7),gpx2dat_vir);
writel(( readl(gpx2con_vir) & (~(0xF << 28))) | 0x1 << 28,gpx2con_vir);
writel((readl(gpx1con_vir) & ~(0XF<< 0))| (0x1 << 0),gpx1con_vir);
writel((readl(gpf3con_vir) & ~(0XFF<< 16 ))| (0x11 << 16),gpf3con_vir);
}
void gpio_led_iounmap(void)
{
iounmap(gpx2con_vir);
iounmap(gpx1con_vir);
iounmap(gpf3con_vir);
}
static int __init demo_init(void)
{
printk("-----%s-----%d.\n",__FUNCTION__,__LINE__);
major = register_chrdev(0, name, &fops);
if(major < 0){
printk("register_chrdev failed.\n");
}
printk("major :%d.\n",major);
cls = class_create(THIS_MODULE, "chardev");
if(cls == NULL){
goto err0;
}
dev = device_create(cls,NULL,MKDEV(major, 0),NULL, "fsled%d",0);
if(dev == NULL){
printk("device_create failed.\n");
goto err0;
}
//硬件操作
gpio_led_ioremap();
return 0;
err0:
unregister_chrdev(major, name);
return -1;
}
static void __exit demo_exit(void)
{
printk("-----%s-----%d.\n",__FUNCTION__,__LINE__);
gpio_led_iounmap();
device_destroy(cls,MKDEV(major, 0));
class_destroy(cls);
unregister_chrdev(major,name);
}
//模块的三要素:
module_init(demo_init); //入口函数
module_exit(demo_exit);//出口函数
MODULE_LICENSE("GPL");//GPL
下面是mpu6050驱动
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <linux/of.h>
#include <linux/slab.h>
#include <linux/of_irq.h>
#include <linux/interrupt.h>
#include <linux/sched.h>
#include <linux/poll.h>
#include <linux/workqueue.h>
#include <linux/platform_device.h>
#include<linux/ioport.h>
#include <linux/timer.h>
#include <linux/i2c.h>
#include <asm/delay.h>
#include "common.h"
#include "mpu6050.h"
#define GPBCON 0x11400040
void __iomem *gpbcon_vir;
unsigned int major ;
struct class *cls;
struct device *dev;
char kbuf[] = {'1','2','3','4'};
struct i2c_client *mpu_client;
char mpu6050_read(char regaddr)
{
char txbuf[1] = {regaddr};
char rxbuf[1] = {0};
struct i2c_msg msgs[2] = {
{mpu_client->addr,0,1,txbuf},
{mpu_client->addr,1,1,rxbuf}
};
i2c_transfer(mpu_client->adapter,msgs,2);
return rxbuf[0];
}
int mpu6050_write(char reg,char val)
{
char txbuf[] ={reg,val};
struct i2c_msg msgs[] = {
{mpu_client->addr,0,2,txbuf},
};
i2c_transfer(mpu_client->adapter,msgs,1);
return 0;
}
int mpu6050_gpio_init(void)
{
mpu6050_write(MPU_PWR_MGMT1_REG, 0x80);//复位MPU6050
udelay(2000);
mpu6050_write(MPU_PWR_MGMT1_REG, 0x0);//唤醒MPU6050
mpu6050_write(MPU_GYRO_CFG_REG, 0xF8);//陀螺仪传感器,±2000dps
mpu6050_write(MPU_ACCEL_CFG_REG, 0x19);//加速度传感器 2g
// mpu6050_write(MPU_GYRO_CFG_REG, (0x3 << 3));//陀螺仪传感器,±2000dps
// mpu6050_write(MPU_ACCEL_CFG_REG, (0x0 << 3));//加速度传感器 2g
//mpu6050_write(MPU_ACCEL_CFG_REG, 0x01);//唤醒MPU6050
mpu6050_write(MPU_SAMPLE_RATE_REG, 0x07);//设置采æ ·率50Hz
mpu6050_write(MPU_CFG_REG, 0x06);//唤醒MPU6050
#if 1
printk("who am i:0x%x\n", mpu6050_read(0x75));
#endif
return 0;
}
int mpu6050_open(struct inode *inode, struct file *filp)
{
//硬件的初始化工作--收发数据的初始化
printk("---->%s--->%d\n",__func__,__LINE__);
return 0;
}
ssize_t dev_mpu6050_read(struct file *filp, char __user *usrbuf, size_t count, loff_t *offset)
{
int bytes = 0;
printk("---->%s--->%d\n",__func__,__LINE__);
bytes = copy_to_user(usrbuf,kbuf,4);
if(bytes > 0){
printk("copy_to_user failed!\n");
}
return 0;
}
ssize_t dev_mpu6050_write(struct file *filp, const char __user *usrbuf, size_t size, loff_t *offset)
{
int bytes = 0;
printk("---->%s--->%d\n",__func__,__LINE__);
bytes = copy_from_user(kbuf,usrbuf,4);
if(bytes > 0){
printk("copy_from_user failed\n");
return -1;
}
printk("copy_from_user usrbuf:%c\n",kbuf[0]);
return 0;
}
long mpu6050_ioctl(struct file *filp, unsigned int cmd, unsigned long args)
{
struct mpu6050_data data;
// printk("---->%s--->%d\n",__func__,__LINE__);
switch(cmd)
{
case MPU6050_GYRO:
data.gyro.x = mpu6050_read(MPU_GYRO_XOUTL_REG);
data.gyro.x |= mpu6050_read(MPU_GYRO_XOUTH_REG) << 8;
data.gyro.x = mpu6050_read(MPU_GYRO_YOUTL_REG);
data.gyro.x |= mpu6050_read(MPU_GYRO_YOUTH_REG) << 8;
data.gyro.x = mpu6050_read(MPU_GYRO_ZOUTL_REG);
data.gyro.x |= mpu6050_read(MPU_GYRO_ZOUTH_REG) << 8;
break;
case MPU6050_ACCEL:
data.accel.x = mpu6050_read(MPU_ACCEL_XOUTL_REG);
data.accel.x |= mpu6050_read(MPU_ACCEL_XOUTH_REG) << 8;
data.accel.y = mpu6050_read(MPU_ACCEL_YOUTL_REG);
data.accel.y |= mpu6050_read(MPU_ACCEL_YOUTH_REG) << 8;
data.accel.z = mpu6050_read(MPU_ACCEL_ZOUTL_REG);
data.accel.z |= mpu6050_read(MPU_ACCEL_ZOUTH_REG) << 8;
break;
case MPU6050_TEMP:
data.temp = mpu6050_read(MPU_TEMP_OUTL_REG);
data.temp |= mpu6050_read(MPU_TEMP_OUTH_REG) << 8;
break;
default:
printk("sorry, cmd wrong !\n");
}
if (copy_to_user((void *)args, &data, sizeof(data)))
return -EFAULT;
return 0;
}
int mpu6050_close(struct inode *inode, struct file *filp)
{
printk("---->%s--->%d\n",__func__,__LINE__);
return 0;
}
const struct file_operations mpu6050_fops = {
.owner = THIS_MODULE,
.open = mpu6050_open,
.read = dev_mpu6050_read,
.write = dev_mpu6050_write,
.unlocked_ioctl = mpu6050_ioctl,
.release = mpu6050_close,
};
int mpu6050_probe(struct i2c_client *client, struct i2c_device_id *devid)
{
printk("---->%s--->%d\n",__func__,__LINE__);
mpu_client = client;
printk("MPU6050 probe name.....%s\n",devid->name);
printk("MPU6050 probe addr.....%#x\n",client->addr);
major = register_chrdev(0,"mpu6050",&mpu6050_fops);
if(major <= 0){
printk("register_chrdev failed!\n");
}
printk("register_chrdev success .major: %d\n",major);
cls = class_create(THIS_MODULE,"mpu6050");
if(cls == NULL){
printk("class_create failed!\n");
}
dev = device_create(cls, NULL,MKDEV(major,0),NULL,"fsmpu60500");
if(dev == NULL){
printk("device_create failed!\n");
}
// printk("mpu_6050 read who am i :0x%#x\n",mpu6050_read(0x75));
mpu6050_gpio_init();
return 0;
}
int mpu6050_remove(struct i2c_client *mpu_6050)
{
printk("---->%s--->%d\n",__func__,__LINE__);
return 0;
}
struct i2c_device_id mpu6050_id_table[] = {
{},
{},
};
struct of_device_id mpu6050_device_id[] = {
{.compatible = "invensense,mpu6050"},
{},
};
struct i2c_driver mpu6050={
.driver={
.name = "mpu6050",
.of_match_table = of_match_ptr(mpu6050_device_id),
},
.probe = mpu6050_probe,
.remove = mpu6050_remove,
.id_table =mpu6050_id_table,
};
static int __init mpu6050_init(void)
{
printk("---->%s--->%d\n",__func__,__LINE__);
if(i2c_add_driver(&mpu6050)){
printk("driver_register failed\n");
return -1;
}
return 0;
}
static void __exit mpu6050_exit(void)
{
// printk("---->%s--->%d\n",__func__,__LINE__);
// iounmap(gpbcon_vir);
device_destroy(cls,MKDEV(major,0));
class_destroy(cls);
unregister_chrdev(major,"mpu6050");
i2c_del_driver(&mpu6050);
}
module_init(mpu6050_init);
module_exit(mpu6050_exit);
MODULE_LICENSE("GPL");
#if 0
测试结果:
[root@fengjunhui ]:~$ insmod mpu6050.ko
[ 1361.710000] ---->mpu6050_init--->240
[ 1361.710000] ---->mpu6050_probe--->180
[ 1361.715000] MPU6050 probe name.....(null)
[ 1361.720000] MPU6050 probe addr.....0x68
[ 1361.720000] register_chrdev success .major: 253
[ 1361.745000] who am i:0x68
[root@fengjunhui ]:~$ ./app
[ 4315.375000] ---->mpu6050_open--->87
open device succe[ 4315.585000] ---->dev_mpu6050_read--->94
[ 4315.590000] ---->dev_mpu6050_write--->107
[ 4315.595000] copy_from_user usrbuf:9
ss! fd: 3
usrbuf[2] : 3
----------------------------------accel-------------------
accel data: x = 001848, y = 065432, z = 015538
***********************************gyro*******************
gyro data: x = 000005, y = 000000, z = 000002
===================================temp===================
temp data: z = 063159
----------------------------------accel-------------------
accel data: x = 001860, y = 065430, z = 015514
***********************************gyro*******************
gyro data: x = 000005, y = 000000, z = 000002
===================================temp===================
temp data: z = 063159
----------------------------------accel-------------------
accel data: x = 001844, y = 065422, z = 015518
***********************************gyro*******************
gyro data: x = 000005, y = 000000, z = 000002
===================================temp===================
temp data: z = 063160
----------------------------------accel-------------------
accel data: x = 001856, y = 065422, z = 015508
***********************************gyro*******************
gyro data: x = 000005, y = 000000, z = 000002
===================================temp===================
temp data: z = 063156
----------------------------------accel-------------------
accel data: x = 001858, y = 065424, z = 015484
^C[ 4319.900000] ---->mpu6050_close--->165
[root@fengjunhui ]:~$ rmmod mpu6050
[ 4425.180000] ---->mpu6050_exit--->253
[ 4425.185000] ---->mpu6050_remove--->211
#endif
export ARCH=arm
export CROSS_COMPILE=arm-none-linux-gnueabi-#KERNELDIR :=/lib/modules/$(shell uname -r)/build
KERNELDIR :=/home/book/Linux_4412/kernel/linux-3.14
PWD :=$(shell pwd)obj-m += fsmpu6050.o
all:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
arm-none-linux-gnueabi-gcc test.c -o mpu6050_testinstall:
cp mpu6050_test *.ko ~/nfs_rootfs/drv/
clean:
$(MAKE) -C $(KERNELDIR) M=$(PWD) clean
rm -rf mpu6050_test
拿mpu6050的makefile举例
二、A9主框架
主要是数据上传这部分的程序
#include "data_global.h"
#include "sem.h"
#define N 1024 //for share memory
extern int shmid;
extern int msgid;
extern int semid;
extern key_t shm_key;
extern key_t sem_key;
extern key_t key; //msg_key
extern pthread_mutex_t mutex_client_request,
mutex_refresh,
mutex_sqlite,
mutex_transfer,
mutex_analysis,
mutex_sms,
mutex_buzzer,
mutex_led,
mutex_camera;
extern pthread_cond_t cond_client_request,
cond_refresh,
cond_sqlite,
cond_transfer,
cond_analysis,
cond_sms,
cond_buzzer,
cond_led,
cond_camera;
extern struct env_info_client_addr sm_all_env_info;
struct shm_addr
{
char shm_status; //shm_status���Ե���home_id���������ֹ����ڴ�����
struct env_info_client_addr sm_all_env_info;
};
struct shm_addr *shm_buf;
int file_env_info_struct(struct env_info_client_addr *rt_status,int home_id);//ģ������ˢ�µĺ���
void *pthread_refresh(void *arg)
{
//semaphore for access to resource limits
if((sem_key = ftok("/tmp",'i')) < 0){
perror("ftok failed .\n");
exit(-1);
}
semid = semget(sem_key,1,IPC_CREAT|IPC_EXCL|0666);
if(semid == -1) {
if(errno == EEXIST){
semid = semget(sem_key,1,0777);
}else{
perror("fail to semget");
exit(1);
}
}else{
init_sem (semid, 0, 1);
}
//share memory for env_info refresh config
if((shm_key = ftok("/tmp",'i')) < 0){
perror("ftok failed .\n");
exit(-1);
}
shmid = shmget(shm_key,N,IPC_CREAT|IPC_EXCL|0666);
if(shmid == -1) {
if(errno == EEXIST){
shmid = shmget(key,N,0777);
}else{
perror("fail to shmget");
exit(1);
}
}
//share memap
if((shm_buf = (struct shm_addr *)shmat(shmid,NULL,0)) == (void *)-1)
{
perror("fail to shmat");
exit(1);
}
printf("pthread_refresh ......>>>>>>>\n");
bzero (shm_buf, sizeof (struct shm_addr));
while(1){
sem_p(semid,0); //P����
shm_buf->shm_status = 1;
int home_id = 1;
#if 1
shm_buf->sm_all_env_info.monitor_no[home_id] = sm_all_env_info.monitor_no[home_id]; //��ʵ�����ϴ�
#else
file_env_info_struct(&shm_buf->sm_all_env_info,shm_buf->shm_status); //ģ�������ϴ�
#endif
sleep(1);
sem_v(semid,0); //v����
pthread_cond_signal(&cond_transfer);
}
}
int file_env_info_struct(struct env_info_client_addr *rt_status,int home_id)
{
int env_info_size = sizeof(struct env_info_client_addr);
// printf("env_info_size = %d.\n",env_info_size);
rt_status->monitor_no[home_id].zigbee_info.temperature = 10.0;
rt_status->monitor_no[home_id].zigbee_info.tempMIN = 2.0;
rt_status->monitor_no[home_id].zigbee_info.tempMAX = 20.0;
rt_status->monitor_no[home_id].zigbee_info.humidity = 20.0;
rt_status->monitor_no[home_id].zigbee_info.humidityMIN = 10.0;
rt_status->monitor_no[home_id].zigbee_info.humidityMAX = 30.0;
rt_status->monitor_no[home_id].zigbee_info.reserved[0] = 0.01;
rt_status->monitor_no[home_id].zigbee_info.reserved[1] = -0.01;
rt_status->monitor_no[home_id].a9_info.adc = 9.0;
rt_status->monitor_no[home_id].a9_info.gyrox = -14.0;
rt_status->monitor_no[home_id].a9_info.gyroy = 20.0;
rt_status->monitor_no[home_id].a9_info.gyroz = 40.0;
rt_status->monitor_no[home_id].a9_info.aacx = 642.0;
rt_status->monitor_no[home_id].a9_info.aacy = -34.0;
rt_status->monitor_no[home_id].a9_info.aacz = 5002.0;
rt_status->monitor_no[home_id].a9_info.reserved[0] = 0.01;
rt_status->monitor_no[home_id].a9_info.reserved[1] = -0.01;
//����stm32���ֵ����ݡ�arduino���ݣ�
return 0;
}
#include "data_global.h"
#include "common.h"
#include "mpu6050.h"
#include <strings.h>
//����ZigBee�����ݺͲɼ���A9ƽ̨�Ĵ���������
int adc_fd;
int mpu_fd;
extern pthread_cond_t cond_transfer;
extern pthread_mutex_t mutex_transfer;
extern struct env_info_client_addr sm_all_env_info;
int file_env_info_a9_zigbee_debug(struct env_info_client_addr *rt_status,int home_id);
int file_env_info_a9_zigbee_stm32(struct env_info_client_addr *rt_status,int home_id);
int printf_sensor_info_debug(struct env_info_client_addr *sm_all_env_info,int home_id);
void *pthread_transfer(void *arg)
{
int home_id = 1;
adc_fd = open(ADC_DEV,O_RDWR);
mpu_fd = open(MPU6050_DEV,O_RDWR);
if((adc_fd == -1) || (mpu_fd == -1)){
printf("open adc or mpu device failed.\n");
}
while(1){
pthread_mutex_lock(&mutex_transfer);
pthread_cond_wait(&cond_transfer,&mutex_transfer);
printf("pthread_analysis and tranfer.\n");
#if 1
file_env_info_a9_zigbee_stm32(&sm_all_env_info,home_id);
#else
file_env_info_a9_zigbee_debug(&sm_all_env_info,home_id);
#endif
pthread_mutex_unlock(&mutex_transfer);
sleep(1);
}
close(adc_fd);
close(mpu_fd);
}
int file_env_info_a9_zigbee_debug(struct env_info_client_addr *rt_status,int home_id)
{
static int temp = 0;
int env_info_size = sizeof(struct env_info_client_addr);
// printf("env_info_size = %d.\n",env_info_size);
rt_status->monitor_no[home_id].zigbee_info.temperature = 10.0;
rt_status->monitor_no[home_id].zigbee_info.tempMIN = 2.0;
rt_status->monitor_no[home_id].zigbee_info.tempMAX = 20.0;
rt_status->monitor_no[home_id].zigbee_info.humidity = 20.0;
rt_status->monitor_no[home_id].zigbee_info.humidityMIN = 10.0;
rt_status->monitor_no[home_id].zigbee_info.humidityMAX = 30.0;
rt_status->monitor_no[home_id].zigbee_info.reserved[0] = 0.01;
rt_status->monitor_no[home_id].zigbee_info.reserved[1] = -0.01;
temp ++;
rt_status->monitor_no[home_id].a9_info.adc = temp;
rt_status->monitor_no[home_id].a9_info.gyrox = -14.0;
rt_status->monitor_no[home_id].a9_info.gyroy = 20.0;
rt_status->monitor_no[home_id].a9_info.gyroz = 40.0;
rt_status->monitor_no[home_id].a9_info.aacx = 642.0;
rt_status->monitor_no[home_id].a9_info.aacy = -34.0;
rt_status->monitor_no[home_id].a9_info.aacz = 5002.0;
rt_status->monitor_no[home_id].a9_info.reserved[0] = 0.01;
rt_status->monitor_no[home_id].a9_info.reserved[1] = -0.01;
printf_sensor_info_debug(rt_status,home_id);
//����stm32���ֵ����ݡ�arduino���ݣ�
return 0;
}
#if 0
int get_sensor_data_from_a9(struct makeru_a9_info* a9_sensor_data)
{
int adc_sensor_data;
struct mpu6050_data data;
/*get adc sensor data*/
read(adc_fd,&adc_sensor_data,4);
printf("adc value :%0.2fV.\n",(1.8*adc_sensor_data)/4096);
/* get mpu6050 sensor data*/
ioctl(mpu_fd,MPU6050_GYRO,&data);
printf("gyro data: x = %05d, y = %05d, z = %05d\n", data.gyro.x,data.gyro.y,data.gyro.z);
ioctl(mpu_fd,MPU6050_ACCEL,&data);
printf("accel data: x = %05d, y = %05d, z = %05d\n", data.accel.x,data.accel.y,data.accel.z);
/*Ԥ���䣬�е��˷ѿռ䣬���ҿ����Ż�һ��*/
a9_sensor_data->adc = (1.8 * adc_sensor_data)/4096 * 100; //����δint32,Ӧ����float,�Ŵ�100��������С��λ
a9_sensor_data->gyrox = data.gyro.x;
a9_sensor_data->gyroy = data.gyro.y;
a9_sensor_data->gyroz = data.gyro.z;
a9_sensor_data->aacx = data.accel.x;
a9_sensor_data->aacy = data.accel.y;
a9_sensor_data->aacz = data.accel.z;
return 0;
}
#endif
int file_env_info_a9_zigbee_stm32(struct env_info_client_addr *rt_status,int home_id)
{
int env_info_size = sizeof(struct env_info_client_addr);
printf("env_info_size = %d.\n",env_info_size);
rt_status->monitor_no[home_id].zigbee_info.head[0] = 'm';
rt_status->monitor_no[home_id].zigbee_info.head[1] = 's';
rt_status->monitor_no[home_id].zigbee_info.head[2] = 'm';
rt_status->monitor_no[home_id].zigbee_info.head[3] = 'z';
rt_status->monitor_no[home_id].zigbee_info.temperature = 10.0;
rt_status->monitor_no[home_id].zigbee_info.tempMIN = 2.0;
rt_status->monitor_no[home_id].zigbee_info.tempMAX = 20.0;
rt_status->monitor_no[home_id].zigbee_info.humidity = 20.0;
rt_status->monitor_no[home_id].zigbee_info.humidityMIN = 10.0;
rt_status->monitor_no[home_id].zigbee_info.humidityMAX = 30.0;
rt_status->monitor_no[home_id].zigbee_info.reserved[0] = 0.01;
rt_status->monitor_no[home_id].zigbee_info.reserved[1] = -0.01;
//��ȡ����
int adc_sensor_data;
struct mpu6050_data data;
/*get adc sensor data*/
read(adc_fd,&adc_sensor_data,4); /*�����������������Ǽ��������ˣ�ͬ־��Ҫע����......*/
//printf("adc value :%0.2fV.\n",(1.8*adc_sensor_data)/4096);
rt_status->monitor_no[home_id].a9_info.adc = (float)((1.8*adc_sensor_data)/4096);
/* get mpu6050 sensor data*/
ioctl(mpu_fd,MPU6050_GYRO,&data);
//printf("gyro data: x = %d, y = %d, z = %d\n", data.gyro.x,data.gyro.y,data.gyro.z);
ioctl(mpu_fd,MPU6050_ACCEL,&data);
//printf("accel data: x = %d, y = %d, z = %d\n", data.accel.x,data.accel.y,data.accel.z);
rt_status->monitor_no[home_id].a9_info.head[0] = 'm';
rt_status->monitor_no[home_id].a9_info.head[1] = 's';
rt_status->monitor_no[home_id].a9_info.head[2] = 'm';
rt_status->monitor_no[home_id].a9_info.head[3] = 'a';
rt_status->monitor_no[home_id].a9_info.gyrox = (short)data.gyro.x;
rt_status->monitor_no[home_id].a9_info.gyroy = (short)data.gyro.y;
rt_status->monitor_no[home_id].a9_info.gyroz = (short)data.gyro.z;
rt_status->monitor_no[home_id].a9_info.aacx = (short)data.accel.x;
rt_status->monitor_no[home_id].a9_info.aacy = (short)data.accel.y;
rt_status->monitor_no[home_id].a9_info.aacz = (short)data.accel.z;
rt_status->monitor_no[home_id].a9_info.reserved[0] = 0.01;
rt_status->monitor_no[home_id].a9_info.reserved[1] = -0.01;
//printf_sensor_info_debug(rt_status,home_id);
//����stm32���ֵ����ݡ�arduino���ݣ�
return 0;
}
int printf_sensor_info_debug(struct env_info_client_addr *sm_all_env_info,int home_id)
{
printf("a9_info.adc : %f.\n",sm_all_env_info->monitor_no[home_id].a9_info.adc );
printf("a9_info.gyrox: %d.\n",sm_all_env_info->monitor_no[home_id].a9_info.gyrox);
printf("a9_info.gyroy: %d.\n",sm_all_env_info->monitor_no[home_id].a9_info.gyroy);
printf("a9_info.gyroz: %d.\n",sm_all_env_info->monitor_no[home_id].a9_info.gyroz);
printf("a9_info.aacx : %d.\n",sm_all_env_info->monitor_no[home_id].a9_info.aacx );
printf("a9_info.aacy : %d.\n",sm_all_env_info->monitor_no[home_id].a9_info.aacy );
printf("a9_info.aacz : %d.\n",sm_all_env_info->monitor_no[home_id].a9_info.aacz );
printf("a9_info.reserved[0]: %d.\n",sm_all_env_info->monitor_no[home_id].a9_info.reserved[0] );
printf("a9_info.reserved[1]: %d.\n",sm_all_env_info->monitor_no[home_id].a9_info.reserved[1] );
return 0;
}
三、脚本及数据上传实验
写一个插入模块的脚本