From 9f111ce5035f528d0990bc38243ce269619c1efb Mon Sep 17 00:00:00 2001 From: ovdiyuk Date: Mon, 7 Jan 2019 14:19:18 +0200 Subject: [PATCH 1/3] mpu6050: Made module loadable Updated Makefile to build on OrangePI Updated C file: corrected errors --- mpu6050/Makefile | 18 +++ mpu6050/mpu6050-regs.h | 33 +++++ mpu6050/mpu6050.c | 296 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 347 insertions(+) create mode 100644 mpu6050/Makefile create mode 100644 mpu6050/mpu6050-regs.h create mode 100644 mpu6050/mpu6050.c diff --git a/mpu6050/Makefile b/mpu6050/Makefile new file mode 100644 index 0000000..41420b3 --- /dev/null +++ b/mpu6050/Makefile @@ -0,0 +1,18 @@ +# +# mpu6050 accelerometer & gyroscope +# +KERNELDIR+=/lib/modules/4.14.84-sunxi/build +CURDIR:=$(shell pwd) +obj-m := mpu6050.o + +# export ARCH = arm +# export CROSS_COMPILE ?= arm-linux-gnueabihf- + +.PHONY: all clean + +all: + $(MAKE) -C $(KERNELDIR) M=$(CURDIR) modules + +clean: + $(MAKE) -C $(KERNELDIR) M=$(CURDIR) clean + diff --git a/mpu6050/mpu6050-regs.h b/mpu6050/mpu6050-regs.h new file mode 100644 index 0000000..9d51680 --- /dev/null +++ b/mpu6050/mpu6050-regs.h @@ -0,0 +1,33 @@ +#ifndef _MPU6050_REGS_H +#define _MPU6050_REGS_H + +/* Registed addresses */ +#define REG_CONFIG 0x1A +#define REG_GYRO_CONFIG 0x1B +#define REG_ACCEL_CONFIG 0x1C +#define REG_FIFO_EN 0x23 +#define REG_INT_PIN_CFG 0x37 +#define REG_INT_ENABLE 0x38 +#define REG_ACCEL_XOUT_H 0x3B +#define REG_ACCEL_XOUT_L 0x3C +#define REG_ACCEL_YOUT_H 0x3D +#define REG_ACCEL_YOUT_L 0x3E +#define REG_ACCEL_ZOUT_H 0x3F +#define REG_ACCEL_ZOUT_L 0x40 +#define REG_TEMP_OUT_H 0x41 +#define REG_TEMP_OUT_L 0x42 +#define REG_GYRO_XOUT_H 0x43 +#define REG_GYRO_XOUT_L 0x44 +#define REG_GYRO_YOUT_H 0x45 +#define REG_GYRO_YOUT_L 0x46 +#define REG_GYRO_ZOUT_H 0x47 +#define REG_GYRO_ZOUT_L 0x48 +#define REG_USER_CTRL 0x6A +#define REG_PWR_MGMT_1 0x6B +#define REG_PWR_MGMT_2 0x6C +#define REG_WHO_AM_I 0x75 + +/* Register values */ +#define MPU6050_WHO_AM_I 0x68 + +#endif /* _MPU6050_REGS_H */ diff --git a/mpu6050/mpu6050.c b/mpu6050/mpu6050.c new file mode 100644 index 0000000..52edbc8 --- /dev/null +++ b/mpu6050/mpu6050.c @@ -0,0 +1,296 @@ +#include +#include +#include +#include +#include +#include + +#include "mpu6050-regs.h" + + +struct mpu6050_data { + struct i2c_client *drv_client; + int accel_values[3]; + int gyro_values[3]; + int temperature; +}; + +static struct mpu6050_data g_mpu6050_data; + +static int mpu6050_read_data(void) +{ + int temp; + struct i2c_client *drv_client = g_mpu6050_data.drv_client; + + if (drv_client == 0) + return -ENODEV; + + /* accel */ + g_mpu6050_data.accel_values[0] = (s16)((u16)i2c_smbus_read_word_swapped(drv_client, REG_ACCEL_XOUT_H)); + g_mpu6050_data.accel_values[1] = (s16)((u16)i2c_smbus_read_word_swapped(drv_client, REG_ACCEL_YOUT_H)); + g_mpu6050_data.accel_values[2] = (s16)((u16)i2c_smbus_read_word_swapped(drv_client, REG_ACCEL_ZOUT_H)); + /* gyro */ + g_mpu6050_data.gyro_values[0] = (s16)((u16)i2c_smbus_read_word_swapped(drv_client, REG_GYRO_XOUT_H)); + g_mpu6050_data.gyro_values[1] = (s16)((u16)i2c_smbus_read_word_swapped(drv_client, REG_GYRO_YOUT_H)); + g_mpu6050_data.gyro_values[2] = (s16)((u16)i2c_smbus_read_word_swapped(drv_client, REG_GYRO_ZOUT_H)); + /* Temperature in degrees C = + * (TEMP_OUT Register Value as a signed quantity)/340 + 36.53 + */ + temp = (s16)((u16)i2c_smbus_read_word_swapped(drv_client, REG_TEMP_OUT_H)); + g_mpu6050_data.temperature = (temp + 12420 + 170) / 340; + + dev_info(&drv_client->dev, "sensor data read:\n"); + dev_info(&drv_client->dev, "ACCEL[X,Y,Z] = [%d, %d, %d]\n", + g_mpu6050_data.accel_values[0], + g_mpu6050_data.accel_values[1], + g_mpu6050_data.accel_values[2]); + dev_info(&drv_client->dev, "GYRO[X,Y,Z] = [%d, %d, %d]\n", + g_mpu6050_data.gyro_values[0], + g_mpu6050_data.gyro_values[1], + g_mpu6050_data.gyro_values[2]); + dev_info(&drv_client->dev, "TEMP = %d\n", + g_mpu6050_data.temperature); + + return 0; +} + +static int mpu6050_probe(struct i2c_client *drv_client, + const struct i2c_device_id *id) +{ + int ret; + + dev_info(&drv_client->dev, + "i2c client address is 0x%X\n", drv_client->addr); + + /* Read who_am_i register */ + ret = i2c_smbus_read_byte_data(drv_client, REG_WHO_AM_I); + if (IS_ERR_VALUE(ret)) { + dev_err(&drv_client->dev, + "i2c_smbus_read_byte_data() failed with error: %d\n", + ret); + return ret; + } + if (ret != MPU6050_WHO_AM_I) { + dev_err(&drv_client->dev, + "wrong i2c device found: expected 0x%X, found 0x%X\n", + MPU6050_WHO_AM_I, ret); + return -1; + } + dev_info(&drv_client->dev, + "i2c mpu6050 device found, WHO_AM_I register value = 0x%X\n", + ret); + + /* Setup the device */ + /* No error handling here! */ + i2c_smbus_write_byte_data(drv_client, REG_CONFIG, 0); + i2c_smbus_write_byte_data(drv_client, REG_GYRO_CONFIG, 0); + i2c_smbus_write_byte_data(drv_client, REG_ACCEL_CONFIG, 0); + i2c_smbus_write_byte_data(drv_client, REG_FIFO_EN, 0); + i2c_smbus_write_byte_data(drv_client, REG_INT_PIN_CFG, 0); + i2c_smbus_write_byte_data(drv_client, REG_INT_ENABLE, 0); + i2c_smbus_write_byte_data(drv_client, REG_USER_CTRL, 0); + i2c_smbus_write_byte_data(drv_client, REG_PWR_MGMT_1, 0); + i2c_smbus_write_byte_data(drv_client, REG_PWR_MGMT_2, 0); + + g_mpu6050_data.drv_client = drv_client; + + dev_info(&drv_client->dev, "i2c driver probed\n"); + return 0; +} + +static int mpu6050_remove(struct i2c_client *drv_client) +{ + g_mpu6050_data.drv_client = 0; + + dev_info(&drv_client->dev, "i2c driver removed\n"); + return 0; +} + +static const struct i2c_device_id mpu6050_idtable[] = { + { "mpu6050", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, mpu6050_idtable); + +static struct i2c_driver mpu6050_i2c_driver = { + .driver = { + .name = "gl_mpu6050", + }, + + .probe = mpu6050_probe, + .remove = mpu6050_remove, + .id_table = mpu6050_idtable, +}; + +static ssize_t accel_x_show(struct class *class, + struct class_attribute *attr, char *buf) +{ + mpu6050_read_data(); + + sprintf(buf, "%d\n", g_mpu6050_data.accel_values[0]); + return strlen(buf); +} + +static ssize_t accel_y_show(struct class *class, + struct class_attribute *attr, char *buf) +{ + mpu6050_read_data(); + + sprintf(buf, "%d\n", g_mpu6050_data.accel_values[1]); + return strlen(buf); +} + +static ssize_t accel_z_show(struct class *class, + struct class_attribute *attr, char *buf) +{ + mpu6050_read_data(); + + sprintf(buf, "%d\n", g_mpu6050_data.accel_values[2]); + return strlen(buf); +} + +static ssize_t gyro_x_show(struct class *class, + struct class_attribute *attr, char *buf) +{ + mpu6050_read_data(); + + sprintf(buf, "%d\n", g_mpu6050_data.gyro_values[0]); + return strlen(buf); +} + +static ssize_t gyro_y_show(struct class *class, + struct class_attribute *attr, char *buf) +{ + mpu6050_read_data(); + + sprintf(buf, "%d\n", g_mpu6050_data.gyro_values[1]); + return strlen(buf); +} + +static ssize_t gyro_z_show(struct class *class, + struct class_attribute *attr, char *buf) +{ + mpu6050_read_data(); + + sprintf(buf, "%d\n", g_mpu6050_data.gyro_values[2]); + return strlen(buf); +} + +static ssize_t temp_show(struct class *class, + struct class_attribute *attr, char *buf) +{ + mpu6050_read_data(); + + sprintf(buf, "%d\n", g_mpu6050_data.temperature); + return strlen(buf); +} + +CLASS_ATTR_RO(accel_x); +CLASS_ATTR_RO(accel_y); +CLASS_ATTR_RO(accel_z); +CLASS_ATTR_RO(gyro_x); +CLASS_ATTR_RO(gyro_y); +CLASS_ATTR_RO(gyro_z); +CLASS_ATTR_RO(temp); + +static struct class *attr_class; + +static int mpu6050_init(void) +{ + int ret; + + /* Create i2c driver */ + ret = i2c_add_driver(&mpu6050_i2c_driver); + if (ret) { + pr_err("mpu6050: failed to add new i2c driver: %d\n", ret); + return ret; + } + pr_info("mpu6050: i2c driver created\n"); + + /* Create class */ + attr_class = class_create(THIS_MODULE, "mpu6050"); + if (IS_ERR(attr_class)) { + ret = PTR_ERR(attr_class); + pr_err("mpu6050: failed to create sysfs class: %d\n", ret); + return ret; + } + pr_info("mpu6050: sysfs class created\n"); + + /* Create accel_x */ + ret = class_create_file(attr_class, &class_attr_accel_x); + if (ret) { + pr_err("mpu6050: failed to create sysfs class attribute accel_x: %d\n", ret); + return ret; + } + /* Create accel_y */ + ret = class_create_file(attr_class, &class_attr_accel_y); + if (ret) { + pr_err("mpu6050: failed to create sysfs class attribute accel_y: %d\n", ret); + return ret; + } + /* Create accel_z */ + ret = class_create_file(attr_class, &class_attr_accel_z); + if (ret) { + pr_err("mpu6050: failed to create sysfs class attribute accel_z: %d\n", ret); + return ret; + } + /* Create gyro_x */ + ret = class_create_file(attr_class, &class_attr_gyro_x); + if (ret) { + pr_err("mpu6050: failed to create sysfs class attribute gyro_x: %d\n", ret); + return ret; + } + /* Create gyro_y */ + ret = class_create_file(attr_class, &class_attr_gyro_y); + if (ret) { + pr_err("mpu6050: failed to create sysfs class attribute gyro_y: %d\n", ret); + return ret; + } + /* Create gyro_z */ + ret = class_create_file(attr_class, &class_attr_gyro_z); + if (ret) { + pr_err("mpu6050: failed to create sysfs class attribute gyro_z: %d\n", ret); + return ret; + } + /* Create temperature */ + ret = class_create_file(attr_class, &class_attr_temp); + if (ret) { + pr_err("mpu6050: failed to create sysfs class attribute temperature: %d\n", ret); + return ret; + } + + pr_info("mpu6050: sysfs class attributes created\n"); + + pr_info("mpu6050: module loaded\n"); + return 0; +} + +static void mpu6050_exit(void) +{ + if (attr_class) { + class_remove_file(attr_class, &class_attr_accel_x); + class_remove_file(attr_class, &class_attr_accel_y); + class_remove_file(attr_class, &class_attr_accel_z); + class_remove_file(attr_class, &class_attr_gyro_x); + class_remove_file(attr_class, &class_attr_gyro_y); + class_remove_file(attr_class, &class_attr_gyro_z); + class_remove_file(attr_class, &class_attr_temp); + pr_info("mpu6050: sysfs class attributes removed\n"); + + class_destroy(attr_class); + pr_info("mpu6050: sysfs class destroyed\n"); + } + + i2c_del_driver(&mpu6050_i2c_driver); + pr_info("mpu6050: i2c driver deleted\n"); + + pr_info("mpu6050: module exited\n"); +} + +module_init(mpu6050_init); +module_exit(mpu6050_exit); + +MODULE_AUTHOR("Andriy.Khulap "); +MODULE_DESCRIPTION("mpu6050 I2C acc&gyro"); +MODULE_LICENSE("GPL"); +MODULE_VERSION("0.2"); From 0a537f42d078c284abd4e2368e7421e7719c188e Mon Sep 17 00:00:00 2001 From: ovdiyuk Date: Sun, 6 Jan 2019 05:07:35 +0200 Subject: [PATCH 2/3] mpu6050: Shell scripts for Driver insmod and rmmod scripts are added gui_mpu6050.sh script added for pulling information in console --- mpu6050/gui_mpu6050.sh | 142 +++++++++++++++++++++++++++++++++++++++++ mpu6050/ins_mod.sh | 4 ++ mpu6050/rm_mod.sh | 3 + 3 files changed, 149 insertions(+) create mode 100755 mpu6050/gui_mpu6050.sh create mode 100755 mpu6050/ins_mod.sh create mode 100755 mpu6050/rm_mod.sh diff --git a/mpu6050/gui_mpu6050.sh b/mpu6050/gui_mpu6050.sh new file mode 100755 index 0000000..4e8b851 --- /dev/null +++ b/mpu6050/gui_mpu6050.sh @@ -0,0 +1,142 @@ + # !/bin/sh +# xxxxx$ reset And all will be corrected... + +draw_ui () { + # Set up the screen per scan and prepare for the bargraph. + clear + printf $WOB" GYRO \n" + printf $WOB" -30 -20 -10 0 10 20 30 x1000\n" + printf $WOB" ---+----+----+----+----+----+----+----+----+----+----+----+----+---\n" + printf $YOB"X(| |) $GYRO_X\n" + printf $GOB"Y(| |) $GYRO_Y\n" + printf $ROB"Z(| |) $GYRO_Z\n" + printf $WOB" ---+----+----+----+----+----+----+----+----+----+----+----+----+---\n\n" + printf $WOB" ACCEL \n" + printf $WOB" -30 -20 -10 0 10 20 30 x1000\n" + printf $WOB" ---+----+----+----+----+----+----+----+----+----+----+----+----+---\n" + printf $YOB"X(| |) $ACCEL_X\n" + printf $GOB"Y(| |) $ACCEL_Y\n" + printf $ROB"Z(| |) $ACCEL_Z\n" + printf $WOB" ---+----+----+----+----+----+----+----+----+----+----+----+----+---\n\n" + printf $WOB" TEMP \n" + printf $WOB" -20 0 20 40 60 80 100 x1\n" + printf $WOB" ---+----+----+----+----+----+----+----+----+----+----+----+----+---\n" + printf $WOB"T(| |) $TEMP\n" + printf $WOB" ---+----+----+----+----+----+----+----+----+----+----+----+----+---\n\n" +} + +random_data () { + # Mock data for tests + GYRO_X=$[($RANDOM % (64/1))] + GYRO_X=$(( ($GYRO_X-32)*1000 )) + + GYRO_Y=$[($RANDOM % (64/1))] + GYRO_Y=$(( ($GYRO_Y-32)*1000 )) + + GYRO_Z=$[($RANDOM % (64/1))] + GYRO_Z=$(( ($GYRO_Z-32)*1000 )) + + ACCEL_X=$[($RANDOM % (64/1))] + ACCEL_X=$(( ($ACCEL_X-32)*1000 )) + + ACCEL_Y=$[($RANDOM % (64/1))] + ACCEL_Y=$(( ($ACCEL_Y-32)*1000 )) + + ACCEL_Z=$[($RANDOM % (64/1))] + ACCEL_Z=$(( ($ACCEL_Z-32)*1000 )) + + TEMP=$[($RANDOM % (64/1))] + TEMP=$(( ($TEMP-13)*2 )) +} + +read_data () { + GYRO_X=$(cat /sys/class/mpu6050/gyro_x) + GYRO_Y=$(cat /sys/class/mpu6050/gyro_y) + GYRO_Z=$(cat /sys/class/mpu6050/gyro_z) + + ACCEL_X=$(cat /sys/class/mpu6050/accel_x) + ACCEL_Y=$(cat /sys/class/mpu6050/accel_y) + ACCEL_Z=$(cat /sys/class/mpu6050/accel_z) + + TEMP=$(cat /sys/class/mpu6050/temp) +} + +draw_graph () { + GYRO_VAL=$1 + LINE_NUM=$2 + COLOR1=$3 + COLOR2=$4 + + BARGRAPH_GYRO=$COLOR1"\x1B[$LINE_NUM;2f(|"$COLOR2 + for color in $(seq 1 "$GYRO_VAL") + do + BARGRAPH_GYRO=$BARGRAPH_GYRO" " + done + printf "$BARGRAPH_GYRO"$COLOR1"\n" +} + +############### +# GLOBAL VARs # +############### + +# White On Black. +WOB="\x1B[1;37;40m" +#Bleck on white +BOW="\x1B[1;30;47m" +# Black On Green. +BOG="\x1B[1;30;42m" +# Black On Yellow. +BOY="\x1B[1;30;43m" +# Black On red. +BOR="\x1B[1;30;41m" +# Green On Black. +GOB="\x1B[1;32;40m" +# Yellow On Black. +YOB="\x1B[1;33;40m" +# Red On Black. +ROB="\x1B[1;31;40m" + +# Set the pseudo value to zero. +DEPTH=0 +GYRO_X=0 +GYRO_Y=0 +GYRO_Z=0 +ACCEL_X=0 +ACCEL_Y=0 +ACCEL_Z=0 +TEMP=0 + +################ +# Main Script ## +################ + +# Do a clear screen to White On Black. +printf $WOB +clear + +while true +do + # random_data # mock random data generating + read_data # real data read + draw_ui + + #Scale values to bar size + GYRO_X=$(( ${GYRO_X%%.*}/1000+33 )) + GYRO_Y=$(( ${GYRO_Y%%.*}/1000+33 )) + GYRO_Z=$(( ${GYRO_Z%%.*}/1000+33 )) + ACCEL_X=$(( ${ACCEL_X%%.*}/1000+33 )) + ACCEL_Y=$(( ${ACCEL_Y%%.*}/1000+33 )) + ACCEL_Z=$(( ${ACCEL_Z%%.*}/1000+33 )) + TEMP=$(( ${TEMP%%.*}/2+13 )) + + #Draw bars + draw_graph $GYRO_X 4 $YOB $BOY + draw_graph $GYRO_Y 5 $GOB $BOG + draw_graph $GYRO_Z 6 $ROB $BOR + draw_graph $ACCEL_X 12 $YOB $BOY + draw_graph $ACCEL_Y 13 $GOB $BOG + draw_graph $ACCEL_Z 14 $ROB $BOR + draw_graph $TEMP 20 $WOB $BOW + + sleep 0.05 +done diff --git a/mpu6050/ins_mod.sh b/mpu6050/ins_mod.sh new file mode 100755 index 0000000..6ce3bc3 --- /dev/null +++ b/mpu6050/ins_mod.sh @@ -0,0 +1,4 @@ +#!/bin/bash + sudo insmod mpu6050.ko + sudo sh -c "echo mpu6050 0x68 > /sys/bus/i2c/devices/i2c-0/new_device" + \ No newline at end of file diff --git a/mpu6050/rm_mod.sh b/mpu6050/rm_mod.sh new file mode 100755 index 0000000..b7c2608 --- /dev/null +++ b/mpu6050/rm_mod.sh @@ -0,0 +1,3 @@ +#!/bin/bash +sudo sh -c "echo 0x68 > /sys/bus/i2c/devices/i2c-0/delete_device" +sudo rmmod mpu6050.ko From faf9c69f53c81a2ce1e6332f2642d04b7982b761 Mon Sep 17 00:00:00 2001 From: ovdiyuk Date: Mon, 7 Jan 2019 03:13:58 +0200 Subject: [PATCH 3/3] mpu6050: Shell scripts for i2c-tool implemented get_temperature.sh to get Temp via i2c-tool --- mpu6050_scripts/get_temperature.sh | 36 ++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100755 mpu6050_scripts/get_temperature.sh diff --git a/mpu6050_scripts/get_temperature.sh b/mpu6050_scripts/get_temperature.sh new file mode 100755 index 0000000..8d04bd8 --- /dev/null +++ b/mpu6050_scripts/get_temperature.sh @@ -0,0 +1,36 @@ +#!/bin/bash +#Init +sudo i2cset -y 0 0x68 0x6B 0 + +while true +do + +#Read data +UB=$(sudo i2cget -y 0 0x68 0x41) +LB=$(sudo i2cget -y 0 0x68 0x42) + +#Upper Bit + Lower Bit +TEMP=$(( (UB<<8)+LB-65535 )) + +# Calc C value +TEMP_C=$(bc << EOF + scale = 2 + a = ( $TEMP / 340 ) + a + 36.53 +EOF +) + +# Convert C to F value +TEMP_F=$(bc << EOF + scale = 2 + a = ( $TEMP_C * 9 ) + b = ( a / 5 ) + b + 32 +EOF +) + +clear +printf "\n Temp C = $TEMP_C ; Temp F = $TEMP_F" +sleep 1 + +done