嵌入式学习--spi子系统学习(示例程序)

嵌入式学习–spi子系统学习

spi_drv.h

#ifndef SPI_DRV_H
#define SPI_DRV_H
#define ICM20608G_ID		0XAF
#define ICM20608D_ID		0XAE

/* 陀螺仪和加速度自测(出产时设置,用于与用户的自检输出值比较) */
#define ICM20608_SELF_TEST_X_GYRO		0X00
#define ICM20608_SELF_TEST_Y_GYRO		0X01
#define ICM20608_SELF_TEST_Z_GYRO		0X02
#define ICM20608_SELF_TEST_X_ACCEL		0X0D
#define ICM20608_SELF_TEST_Y_ACCEL		0X0E
#define ICM20608_SELF_TEST_Z_ACCEL		0X0F

/* 陀螺仪静态偏移 */
#define ICM20608_XG_OFFS_USRH		0X13
#define ICM20608_XG_OFFS_USRL		0X14
#define ICM20608_YG_OFFS_USRH		0X15
#define ICM20608_YG_OFFS_USRL		0X16
#define ICM20608_ZG_OFFS_USRH		0X17
#define ICM20608_ZG_OFFS_USRL		0X18

#define	ICM20608_SMPLRT_DIV				0x19
#define	ICM20608_CONFIG					0x1A
#define	ICM20608_GYRO_CONFIG			0x1B
#define	ICM20608_ACCEL_CONFIG			0x1C
#define	ICM20608_ACCEL_CONFIG2			0x1D
#define	ICM20608_LP_MODE_CFG			0x1E
#define	ICM20608_ACCEL_WOM_THR			0x1F
#define	ICM20608_FIFO_EN				0x23
#define	ICM20608_FSYNC_INT				0x36
#define	ICM20608_INT_PIN_CFG			0x37
#define	ICM20608_INT_ENABLE				0x38
#define	ICM20608_INT_STATUS				0x3A
/* 加速度输出 */
#define	ICM20608_ACCEL_XOUT_H			0x3B
#define	ICM20608_ACCEL_XOUT_L			0x3C
#define	ICM20608_ACCEL_YOUT_H			0x3D
#define	ICM20608_ACCEL_YOUT_L			0x3E
#define	ICM20608_ACCEL_ZOUT_H			0x3F
#define	ICM20608_ACCEL_ZOUT_L			0x40
/* 温度输出 */
#define	ICM20608_TEMP_OUT_H			0x41
#define	ICM20608_TEMP_OUT_L			0x42
/* 陀螺仪输出 */
#define	ICM20608_GYRO_XOUT_H			0x43
#define	ICM20608_GYRO_XOUT_L			0x44
#define	ICM20608_GYRO_YOUT_H			0x45
#define	ICM20608_GYRO_YOUT_L			0x46
#define	ICM20608_GYRO_ZOUT_H			0x47
#define	ICM20608_GYRO_ZOUT_L			0x48

#define	ICM20608_SIGNAL_PATH_RESET		0x68
#define	ICM20608_ACCEL_INTEL_CTRL 		0x69
#define	ICM20608_USER_CTRL				0x6A
#define	ICM20608_PWR_MGMT_1				0x6B
#define	ICM20608_PWR_MGMT_2				0x6C
#define	ICM20608_FIFO_COUNTH			0x72
#define	ICM20608_FIFO_COUNTL			0x73
#define	ICM20608_FIFO_R_W				0x74
#define	ICM20608_WHO_AM_I 				0x75
/* 加速度静态偏移 */
#define	ICM20608_XA_OFFSET_H			0x77
#define	ICM20608_XA_OFFSET_L			0x78
#define	ICM20608_YA_OFFSET_H			0x7A
#define	ICM20608_YA_OFFSET_L			0x7B
#define	ICM20608_ZA_OFFSET_H			0x7D
#define	ICM20608_ZA_OFFSET_L 			0x7E

#endif

spi_drv.c

#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/of_gpio.h>
#include <linux/semaphore.h>
#include <linux/timer.h>
#include <linux/i2c.h>
#include <linux/spi/spi.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>
#include <linux/platform_device.h>
#include <asm/mach/map.h>
#include <asm/uaccess.h>
#include <asm/io.h>

#include "spi_drv.h"

struct icm20608_devices {
	int major;
	dev_t devid;
	struct cdev cdev;
	struct class *class;
	struct device *dev;
	struct device_node *dev_nod;
	int cs_gpio;
	void *private_data;
	signed int gyro_x_adc;		/* 陀螺仪X轴原始值 	 */
	signed int gyro_y_adc;		/* 陀螺仪Y轴原始值		*/
	signed int gyro_z_adc;		/* 陀螺仪Z轴原始值 		*/
	signed int accel_x_adc;		/* 加速度计X轴原始值 	*/
	signed int accel_y_adc;		/* 加速度计Y轴原始值	*/
	signed int accel_z_adc;		/* 加速度计Z轴原始值 	*/
	signed int temp_adc;		/* 温度原始值 */

};

struct icm20608_devices *icm20608_dev;
#if 1
static int icm20608_read_regs(struct icm20608_devices *dev,u8 reg,u8 *buf,u8 len){
	int ret;
	unsigned char txdata[len];
	struct spi_message m;
	struct spi_transfer *t;
	struct spi_device *spi = (struct spi_device *)dev->private_data;

	t = (struct spi_transfer *)kzalloc(sizeof(struct spi_transfer), GFP_KERNEL);
	gpio_set_value(dev->cs_gpio,0);//片选拉低

	//第一次发送要读取寄存器的地址
	txdata[0] = reg | 0x80;
	t->tx_buf = txdata;
	t->len = 1;
	spi_message_init(&m);
	spi_message_add_tail( t, &m);
	ret = spi_sync(spi, &m);

	txdata[0] = 0xff;
	t->tx_buf = buf;
	t->len = len;
	spi_message_init(&m);
	spi_message_add_tail(t, &m);
	ret  = spi_sync(spi, &m);

	kfree(t);
	gpio_set_value(dev->cs_gpio,1);//片选拉高,释放icm20608
	return ret;
}
#endif
#if 0
static int icm20608_read_regs(struct icm20608_devices *dev,u8 reg,u8 *buf,u8 len){

	u8 data = 0;
	struct spi_device *spi = (struct spi_device*)dev->private_data;

	//片选拉低
	gpio_set_value(dev->cs_gpio, 0);
	data = reg | 0x80;

	spi_write(spi, &data, 1);
	spi_read(spi, buf, len);

	gpio_set_value(dev->cs_gpio, 1);
}
#endif
static unsigned char icm20608_read_one_reg(struct icm20608_devices * dev,u8 reg){
	u8 data = 0;
	icm20608_read_regs(dev,reg,&data,1);
	return data;
}

static void icm20608_read_data(struct icm20608_devices *dev){
	unsigned char data[14];
	
	icm20608_read_regs(dev,ICM20608_ACCEL_XOUT_H,data,14);

	dev->accel_x_adc = (signed short)((data[0]<<8)|data[1]);
	dev->accel_y_adc = (signed short)((data[2]<<8)|data[3]);
	dev->accel_z_adc = (signed short)((data[4]<<8)|data[5]);
	dev->temp_adc = (signed short)((data[6]<<8)|data[7]);
	dev->gyro_x_adc = (signed short)((data[8]<<8)|data[9]);
	dev->gyro_y_adc = (signed short)((data[10]<<8)|data[11]);
	dev->gyro_z_adc = (signed short)((data[12]<<8)|data[13]);
}

#if 1
static s32 icm20608_write_regs(struct icm20608_devices *dev,u8 reg,u8 *buf,u8 len){
	int ret;

	unsigned char txdata[len];
	struct spi_message m;
	struct spi_transfer *t;
	struct spi_device *spi = (struct spi_device *)dev->private_data;

	t = kzalloc(sizeof(struct spi_transfer),GFP_KERNEL);
	gpio_set_value(dev->cs_gpio,0);//片选

	//到读取的寄存器
	txdata[0] = reg & ~0x80;//写数据时,寄存器bit8要清零
	t->tx_buf = txdata;//要发送的数据
	t->len = 1;//一个字节
	spi_message_init(&m);//初始化spi_message
	spi_message_add_tail(t, &m);//讲spi_transfer添加到spi_message队列
	ret = spi_sync(spi, &m);//同步发送

	//发送要写的数据
	t->tx_buf = buf;//写入的数据
	t->len = len;//写的字节数
	spi_message_init(&m);
	spi_message_add_tail(t, &m);
	ret = spi_sync(spi, &m);

	kfree(t);
	gpio_set_value(dev->cs_gpio,1);//片选拉高,释放ICm20608
	return ret;
}
#endif

#if 0
static s32 icm20608_write_regs(struct icm20608_devices *dev,u8 reg,u8 *buf,u8 len){
	u8 data = 0;
	struct spi_device *spi = (struct spi_device *)dev->private_data;

	gpio_set_value(dev->cs_gpio,0);

	data = reg & ~0x80;
	spi_write(spi, &data, 1);
	spi_write(spi, buf, len);

	gpio_set_value(dev->cs_gpio,1);
		
		
}
#endif

static void icm20608_write_one_reg(struct icm20608_devices *dev,u8 reg,u8 value){
	//printk("----------icm20608_write_one_reg----------\n");
	u8 buf = value;
	icm20608_write_regs(dev,reg,&buf,1);
}


//02-2-2
static int icm20608_open(struct inode *inod, struct file *filp){
	printk("------------%s-----------\n",__FUNCTION__);
	filp->private_data = icm20608_dev;
	return 0;
}
//02-2-3
static ssize_t icm20608_read(struct file *filp, char __user *buf , size_t size, loff_t *loft){
	//printk("------------%s-----------\n",__FUNCTION__);

	signed int data[7];
	long err = 0;
	struct icm20608_devices *dev = (struct icm20608_devices *)filp->private_data;

	icm20608_read_data(dev);
	data[0] = dev->gyro_x_adc;
	data[1] = dev->gyro_y_adc;
	data[2] = dev->gyro_z_adc;
	data[3] = dev->accel_x_adc;
	data[4] = dev->accel_y_adc;
	data[5] = dev->accel_z_adc;
	data[6] = dev->temp_adc;
	
	err = copy_to_user(buf,data,sizeof(data));
	
	return 0;
}
//02-2-4
static ssize_t icm20608_write(struct file *filp, const char __user *buf, size_t size, loff_t *loft){
	printk("------------%s-----------\n",__FUNCTION__);

	return 0;
}
//02-2-5
static int icm20608_release(struct inode *inod, struct file *filp){
	printk("------------%s-----------\n",__FUNCTION__);
	return 0;
}


//02-2-1
static const struct file_operations icm20608_fops = {
	.owner = THIS_MODULE,
	.open = icm20608_open,
	.read = icm20608_read,
	.write = icm20608_write,
	.release = icm20608_release,
};

//03-5--
void icm20608_reg_init(struct icm20608_devices *dev){

	printk("------------icm20608_reg_init----------------\n");
	u8 value = 0;

	icm20608_write_one_reg(dev,ICM20608_PWR_MGMT_1,0X80);
	mdelay(50);
	icm20608_write_one_reg(dev, ICM20608_PWR_MGMT_1, 0X01);
	mdelay(50);

	value = icm20608_read_one_reg(dev, ICM20608_WHO_AM_I);
	printk("ICM20608 ID = %x\r\n",value);

	icm20608_write_one_reg(dev, ICM20608_SMPLRT_DIV, 0X00);//输出速率是内部采样率
	icm20608_write_one_reg(dev, ICM20608_GYRO_CONFIG, 0X18);//陀螺仪±2000dps量程
	icm20608_write_one_reg(dev, ICM20608_ACCEL_CONFIG, 0X18);//加速度计±16G量程
	icm20608_write_one_reg(dev, ICM20608_CONFIG, 0X04);//陀螺仪低通滤波BW=20Hz 
	icm20608_write_one_reg(dev, ICM20608_ACCEL_CONFIG2, 0X00);//加速度计低通滤波BW=21.2Hz 
	icm20608_write_one_reg(dev, ICM20608_PWR_MGMT_2, 0X00);//打开加速度计和陀螺仪所有轴
	icm20608_write_one_reg(dev, ICM20608_LP_MODE_CFG, 0X00);//关闭低功耗
	icm20608_write_one_reg(dev, ICM20608_FIFO_EN, 0X00);//关闭FIFO
}


//01-1-1 
static int icm20608_probe(struct spi_device *spi){

	printk("---------------icm20608_probe-------------\n");

	//02-1.要和用户打交道,就得用到字符设备那套
	int ret = 0;
	//构建设备号
	if(icm20608_dev->major){
		icm20608_dev->devid = MKDEV(icm20608_dev->major,0);
		register_chrdev_region(icm20608_dev->devid, 1, "icm20608");
	}else{
		alloc_chrdev_region(&icm20608_dev->devid, 0, 1, "icm20608");
		icm20608_dev->major = MAJOR(icm20608_dev->devid);
	} 

	//02-2,,注册设备
	cdev_init(&icm20608_dev->cdev,&icm20608_fops);
	cdev_add(&icm20608_dev->cdev,icm20608_dev->devid,1);

	//02-4
	icm20608_dev->class = class_create(THIS_MODULE, "ICM20608");
	if(IS_ERR(icm20608_dev->class)){
		return PTR_ERR(icm20608_dev->class);
	}

	//02-3,创建设备节点
	icm20608_dev->dev = device_create(icm20608_dev->class, NULL, icm20608_dev->devid, NULL, "peifeng-icm20608");//在/dev/目录下可见
	if(IS_ERR(icm20608_dev->dev)){
		return PTR_ERR(icm20608_dev->dev);
	}

	//03-1
	//icm20608_dev->dev_nod = of_find_node_by_path("/soc/aips-bus@02000000/spba-bus@02000000/ecspi@02010000");
	icm20608_dev->dev_nod = of_get_parent(spi->dev.of_node);
	if(icm20608_dev->dev_nod == NULL){
		printk("find device node failed!!\n");
		return -EINVAL;
	}

	//03-2
	icm20608_dev->cs_gpio = of_get_named_gpio(icm20608_dev->dev_nod, "cs-gpio", 0);
	if(icm20608_dev->cs_gpio < 0){
		printk("can not get cs-gpio!!\n");
		return -EINVAL;
	}
	printk("---------icm20608_dev->cs_gpio = %d \n",icm20608_dev->cs_gpio);
	
	ret = gpio_request(icm20608_dev->cs_gpio, "cs");
	if(ret<0){
		printk("cs_gpio request failed\n");
	}
	printk("---------gpio_request = %d \n",ret);

	//03-3
	ret = gpio_direction_output(icm20608_dev->cs_gpio, 1);
	if(ret < 0){
		printk("can not set gpio!!\n");
		
	}
	printk("---------gpio_direction_output = %d \n",ret);

	//03-4  初始化spi_device
	spi->mode = SPI_MODE_0;//CPOL=0,CPHA=0
	//setup SPI mode and clock rate
	spi_setup(spi);
	icm20608_dev->private_data = spi;

	//03-5 初始化icm20608内部寄存器
	icm20608_reg_init(icm20608_dev);
	return 0;
	
	
}
//01-1-2,,
static int icm20608_remove(struct spi_device *spi){
	cdev_del(&icm20608_dev->cdev);
	unregister_chrdev_region(icm20608_dev->devid, 1);

	device_destroy(icm20608_dev->class, icm20608_dev->devid);
	class_destroy(icm20608_dev->class);

	gpio_free(icm20608_dev->cs_gpio);

	return 0;
}

//01-2 传统匹配方式
static const struct spi_device_id icm20608_id[] = {
	{"peifeng,icm20608",0},
	{},

};

//01-3 设备树匹配列表
static const struct of_device_id icm20608_of_match[] = 
{
	{.compatible = "peifeng,icm20608"},
	{},
};


//01-1,,spi驱动结构体
struct spi_driver icm_20608_drv = {
	.probe = icm20608_probe,
	.remove = icm20608_remove,
	.driver = {
		.owner = THIS_MODULE,
		.name = "icm20608",
		.of_match_table = icm20608_of_match,//对应01-3
	},
	.id_table = icm20608_id,//对应01-2
};


//01.
static int __init spi_drv_init(void){
	printk("---------------%s-----------\n",__FUNCTION__);
	icm20608_dev = (struct icm20608_devices *)kzalloc(sizeof(struct icm20608_devices),GFP_KERNEL);
	if(icm20608_dev == NULL){
		printk("icm20608 kzalloc failed\n");
		return -ENOMEM;
	}

	return spi_register_driver(&icm_20608_drv);
}
///02,
static void __exit spi_drv_exit(void){
	printk("---------------%s-----------\n",__FUNCTION__);

	spi_unregister_driver(&icm_20608_drv);

	kfree(icm20608_dev);
}


module_init(spi_drv_init);
module_exit(spi_drv_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("PEIFENG");


spi_app.c

#include "stdio.h"
#include "unistd.h"
#include "sys/types.h"
#include "sys/stat.h"
#include "sys/ioctl.h"
#include "fcntl.h"
#include "stdlib.h"
#include "string.h"
#include <poll.h>
#include <sys/select.h>
#include <sys/time.h>
#include <signal.h>
#include <fcntl.h>

int main(int argc, char *argv[])
{
	int fd;
	char *filename;
	signed int databuf[7];
	unsigned char data[14];
	signed int gyro_x_adc, gyro_y_adc, gyro_z_adc;
	signed int accel_x_adc, accel_y_adc, accel_z_adc;
	signed int temp_adc;

	float gyro_x_act, gyro_y_act, gyro_z_act;
	float accel_x_act, accel_y_act, accel_z_act;
	float temp_act;

	int ret = 0;

	if (argc != 2) {
		printf("Error Usage!\r\n");
		return -1;
	}

	filename = argv[1];
	fd = open(filename, O_RDWR);
	if(fd < 0) {
		printf("can't open file %s\r\n", filename);
		return -1;
	}

	while (1) {
		ret = read(fd, databuf, sizeof(databuf));
		if(ret == 0) { 			/* 数据读取成功 */
			gyro_x_adc = databuf[0];
			gyro_y_adc = databuf[1];
			gyro_z_adc = databuf[2];
			accel_x_adc = databuf[3];
			accel_y_adc = databuf[4];
			accel_z_adc = databuf[5];
			temp_adc = databuf[6];

			/* 计算实际值 */
			gyro_x_act = (float)(gyro_x_adc)  / 16.4;
			gyro_y_act = (float)(gyro_y_adc)  / 16.4;
			gyro_z_act = (float)(gyro_z_adc)  / 16.4;
			accel_x_act = (float)(accel_x_adc) / 2048;
			accel_y_act = (float)(accel_y_adc) / 2048;
			accel_z_act = (float)(accel_z_adc) / 2048;
			temp_act = ((float)(temp_adc) - 25 ) / 326.8 + 25;


			printf("\r\n 转换前:\r\n");
			printf("gx = %d, gy = %d, gz = %d\r\n", gyro_x_adc, gyro_y_adc, gyro_z_adc);
			printf("ax = %d, ay = %d, az = %d\r\n", accel_x_adc, accel_y_adc, accel_z_adc);
			printf("temp = %d\r\n", temp_adc);
			
			printf(" 转换后:\n");
			printf("act gx = %.2f°/S, act gy = %.2f°/S, act gz = %.2f°/S\r\n", gyro_x_act, gyro_y_act, gyro_z_act);
			printf("act ax = %.2fg, act ay = %.2fg, act az = %.2fg\r\n", accel_x_act, accel_y_act, accel_z_act);
			printf("act temp = %.2f°C\r\n", temp_act);
		}
		usleep(100000); /*100ms */
	}
	close(fd);	/* 关闭文件 */	
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值