查看正点原子IMX6ULL核心板和底板原理图,决定与 icm20608 共用 ecspi3。
找到 “imx6ull-alientek-emmc.dts” 和 “imx6ull-14x14-evk.dts”,在 “&iomuxc”下修改 “pinctrl_ecspi3” 子节点,添加“pinctrl_ads1256”,子节点。
pinctrl_ecspi3: ecspi3grp {
fsl,pins = <
MX6UL_PAD_UART2_RTS_B__ECSPI3_MISO 0x100b1 /* MISO */
MX6UL_PAD_UART2_CTS_B__ECSPI3_MOSI 0x100b1 /* MOSI */
MX6UL_PAD_UART2_RX_DATA__ECSPI3_SCLK 0x100b1 /* CLK */
>;
};
pinctrl_ads1256: ads1256 {
fsl,pins = <
MX6UL_PAD_UART2_TX_DATA__GPIO1_IO20 0x100b0 /* CS0, icm20608片选 */
MX6UL_PAD_UART3_RX_DATA__GPIO1_IO25 0x100b1 /* CS, ads1256片选 */
MX6UL_PAD_GPIO1_IO01__GPIO1_IO01 0x100b1 /* RESET, ads1256复位 */
MX6UL_PAD_JTAG_MOD__GPIO1_IO10 0x130b1 /* DRDY, ads1256就绪 */
>;
};
将使用相同引脚的设备节点设置为“disabled”状态
在“&ecspi3”节点下添加 “ads1256” 节点
&ecspi3 {
fsl,spi-num-chipselects = <1>;
// cs-gpios = <&gpio1 20 GPIO_ACTIVE_LOW &gpio1 25 GPIO_ACTIVE_LOW>;
// cs-gpios = <&gpio1 25 GPIO_ACTIVE_LOW>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_ecspi3>;
status = "okay";
// spi3dev0: icm20608@0 {
// compatible = "alientek,icm20608";
// spi-max-frequency = <8000000>;
// reg = <0>;
// };
spidev: ads1256@0 {
compatible = "alientek,ads1256";
spi-max-frequency = <1000000>;
status = "okay";
reg = <0>;
pinctrl-0 = <&pinctrl_ads1256>;
reset-gpio = <&gpio1 1 GPIO_ACTIVE_LOW>;
drdy-gpio = <&gpio1 10 GPIO_ACTIVE_HIGH>;
cs-gpio = <&gpio1 25 GPIO_ACTIVE_LOW>;
cs0-gpio = <&gpio1 20 GPIO_ACTIVE_LOW>;
};
};
使用开发板资料提供的编译工具,编译设备树文件,更新到开发板。
ads1256.c
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "ads1256.h"
#include
/***************************************************************
Copyright © ALIENTEK Co., Ltd. 1998-2029. All rights reserved.
文件名 : ads1256.c
作者 : 刘明鑫
版本 : V1.0
描述 : ADS1256 SPI驱动程序
其他 : 无
日志 : 初版V1.0 2022/07/31 刘明鑫创建
***************************************************************/
#define ADS1256_CNT 1
#define ADS1256_NAME "ads1256"
#define ADS1256_TRANSFORM_TIME_US 309
/* 总线注册注销 */
static int ads1256_probe(struct spi_device *spi);
static int ads1256_remove(struct spi_device *spi);
/* 文件操作函数集 */
static int ads1256_open(struct inode *inode, struct file *filp);
static ssize_t ads1256_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt);
static ssize_t ads1256_read(struct file *filp, char __user *buf, size_t cnt, loff_t *off);
static int ads1256_release(struct inode *inode, struct file *filp);
struct ads1256_dev
{
dev_t devid; /* 设备号 */
struct cdev cdev; /* cdev */
struct class *class; /* 类 */
struct device *device; /* 设备 */
struct device_node *nd; /* 设备节点 */
int major; /* 主设备号 */
int cs0_gpio; /* icm20608使用的片选,因为接了下拉电阻,所以需要手动上拉,停止启用 */
int cs_gpio; /* cs所使用的GPIO编号 */
int reset_gpio; /* reset所使用的GPIO编号 */
int drdy_gpio; /* drdy所使用的GPIO编号 */
unsigned char channels[8]; /* 采样通道,最多8个 */
unsigned char channel_num; /* 采样通道数量 */
int delay_us; /* 采样间隔时间 */
void *private_data; /* 私有数据 */
};
static struct ads1256_dev ads1256dev;
/* 传统匹配方式ID列表 */
static const struct spi_device_id ads1256_id[] = {
{"alientek,ads1256", 0},
{}};
/* 设备树匹配列表 */
static const struct of_device_id ads1256_of_match[] = {
{.compatible = "alientek,ads1256"},
{/* Sentinel */}};
/* SPI驱动结构体 */
static struct spi_driver ads1256_driver = {
.probe = ads1256_probe,
.remove = ads1256_remove,
.driver = {
.owner = THIS_MODULE,
.name = "ads1256",
.of_match_table = ads1256_of_match,
},
.id_table = ads1256_id,
};
/* ads1256操作函数 */
static const struct file_operations ads1256_ops = {
.owner = THIS_MODULE,
.open = ads1256_open,
.read = ads1256_read,
.write = ads1256_write,
.release = ads1256_release,
};
static int ads1256_transfer_multibyte(struct ads1256_dev *dev, unsigned char *wbuf, unsigned char *rbuf, unsigned char len)
{
int ret = 0;
struct spi_message m;
struct spi_transfer t = {0};
struct spi_device *spi = (struct spi_device *)dev->private_data;
/* 一共发送len个字节的数据*/
t.tx_buf = wbuf; /* 要发送的数据 */
t.rx_buf = rbuf;
t.len = len; /* 传输长度 */
spi_message_init(&m); /* 初始化spi_message */
spi_message_add_tail(&t, &m); /* 将spi_transfer添加到spi_message队列 */
ret = spi_sync(spi, &m); /* 同步发送 */
return -ret;
}
/*
* @description : 数据传输
* @param - dev : ads1256设备
* @param - byte: 要通过spi总线发送的数据
* @return : 通过spi总线接收到的数据
*/
static unsigned char ads1256_transfer(struct ads1256_dev *dev, unsigned char byte)
{
int ret = -1;
unsigned char txdata[1];
unsigned char rxdata[1];
struct spi_message m;
struct spi_transfer t = {0};
struct spi_device *spi = (struct spi_device *)dev->private_data;
/* 一共发送1个字节的数据,第一个字节为
寄存器首地址,一共要读取len个字节长度的数据,*/
txdata[0] = byte | 0x80; /* 写数据的时候首寄存器地址bit8要置1 */
t.tx_buf = txdata; /* 要发送的数据 */
t.rx_buf = rxdata; /* 要读取的数据 */
t.len = 1; /* 发送的长度 */
spi_message_init(&m); /* 初始化spi_message */
spi_message_add_tail(&t, &m); /* 将spi_transfer添加到spi_message队列 */
ret = spi_sync(spi, &m); /* 同步发送 */
if (ret)
{
rxdata[0] = 0;
}
return rxdata[0];
}
static int ads1256_read_channel(struct ads1256_dev *dev, unsigned char channel)
{
unsigned char i = 0;
unsigned int r = 0;
int sum = 0;
unsigned char wbuf[8];
unsigned char rbuf[8];
/* 设置采样通道 */
gpio_set_value(dev->cs_gpio, 0);
while (gpio_get_value(dev->drdy_gpio))
;
wbuf[0] = ADS1256_CMD_WREG | (ADS1256_MUX & 0xF);
wbuf[1] = 0;
ads1256_transfer_multibyte(dev, wbuf, rbuf, 2);
wbuf[0] = channel;
ads1256_transfer_multibyte(dev, wbuf, rbuf, 1);
while (gpio_get_value(dev->drdy_gpio))
;
/* 读取转换结果 */
wbuf[0] = ADS1256_CMD_SYNC;
wbuf[1] = ADS1256_CMD_WAKEUP;
wbuf[2] = ADS1256_CMD_RDATA;
ads1256_transfer_multibyte(dev, wbuf, rbuf, 3);
wbuf[0] = 0xFF;
wbuf[1] = 0xFF;
wbuf[2] = 0xFF;
memset(rbuf, 0, 3);
ads1256_transfer_multibyte(dev, wbuf, rbuf, 3);
for (i = 0; i < 3; i++)
{
sum = sum << 8;
r = rbuf[i];
sum |= r;
}
if (sum > 0x7FFFFF)
{ // 负值转换
sum = sum + 0xFF000000;
}
while (gpio_get_value(dev->drdy_gpio))
;
gpio_set_value(dev->cs_gpio, 1);
return sum;
}
/*
* | 命令 | 参数长度 | 参数 |
* | 1 | 1 | n |
*/
struct write_data
{
unsigned char cmd;
unsigned char length;
unsigned char param[8]; /* 最多8个参数 */
};
static int ads1256_write_string_to_dev(struct ads1256_dev *dev, const char *buf, size_t cnt)
{
size_t index = 0;
struct write_data *data_p;
int temp;
while (index < cnt)
{
if (cnt - index < 3)
{
return index;
}
data_p = (struct write_data *)&buf[index];
switch (data_p->cmd)
{
case SET_CHANNELS:
if (data_p->length > 8 || index + 1 + data_p->length >= cnt)
{
return index;/* 参数错误 或 剩余长度不够 */
}
dev->channel_num = data_p->length; /* 设置通道数量 */
memcpy(dev->channels, data_p->param, dev->channel_num); /* 设置通道序列 */
ads1256_read_channel(dev, dev->channels[0]);/* 重置通道 */
index = index + data_p->length + 2;
break;
case SET_FREQUENCY:
if (data_p->length != 4 || index + 1 + data_p->length >= cnt)
{
return index;/* 参数错误 或 剩余长度不够 */
}
temp = (data_p->param[0] << 24) + (data_p->param[1] << 16) + (data_p->param[2] << 8) + data_p->param[3];
temp = 1000000 / temp - ADS1256_TRANSFORM_TIME_US;
dev->delay_us = temp > 0 ? temp : 0;
index = index + data_p->length + 2;
break;
default:
return index;
}
}
return index;
}
/*
* @description : 打开设备
* @param - inode : 传递给驱动的inode
* @param - filp : 设备文件,file结构体有个叫做pr似有ate_data的成员变量
* 一般在open的时候将private_data似有向设备结构体。
* @return : 0 成功;其他 失败
*/
static int ads1256_open(struct inode *inode, struct file *filp)
{
filp->private_data = &ads1256dev; /* 设置私有数据 */
return 0;
}
/*
* @description : 向设备写数据
* @param - filp : 设备文件,表示打开的文件描述符
* @param - buf : 要写给设备写入的数据
* @param - cnt : 要写入的数据长度
* @param - offt : 相对于文件首地址的偏移
* @return : 写入的字节数,如果为负值,表示写入失败
*/
static ssize_t ads1256_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt)
{
int retvalue;
unsigned char *databuf;
struct ads1256_dev *dev = (struct ads1256_dev *)filp->private_data;
databuf = kzalloc(cnt, GFP_KERNEL);
if (!databuf)
{
return -ENOMEM;
}
retvalue = copy_from_user(databuf, buf, cnt);
if (retvalue < 0)
{
printk("kernel write failed!\r\n");
retvalue = -EFAULT;
goto out1;
}
retvalue = ads1256_write_string_to_dev(dev, databuf, cnt);
out1:
kfree(databuf);
return retvalue;
}
/*
* @description : 从设备读取数据
* @param - filp : 要打开的设备文件(文件描述符)
* @param - buf : 返回给用户空间的数据缓冲区
* @param - cnt : 要读取的数据长度
* @param - offt : 相对于文件首地址的偏移
* @return : 读取的字节数,如果为负值,表示读取失败
*/
static ssize_t ads1256_read(struct file *filp, char __user *buf, size_t cnt, loff_t *off)
{
int err = 0;
int *result;
int length;
int index = 1; /* 从1开始,实际采样是从通道0开始 */
struct ads1256_dev *dev = (struct ads1256_dev *)filp->private_data;
/* 计算采样点个数 */
length = cnt / 4;
/* 开内存空间 */
result = kzalloc(length * 4, GFP_KERNEL);
if (!result)
{
return -ENOMEM;
}
/* 采样 */
while (index < length + 1)
{
result[index - 1] = ads1256_read_channel(dev, dev->channels[index % dev->channel_num]);
index++;
udelay(dev->delay_us);
}
/* 重置通道 */
ads1256_read_channel(dev, dev->channels[0]);
err = copy_to_user(buf, result, length * 4);
kfree(result);
return length * 4;
}
/*
* @description : 关闭/释放设备
* @param - filp : 要关闭的设备文件(文件描述符)
* @return : 0 成功;其他 失败
*/
static int ads1256_release(struct inode *inode, struct file *filp)
{
return 0;
}
/*
* ads1256内部寄存器初始化函数
* @param : 无
* @return : 无
*/
void ads1256_reginit(struct ads1256_dev *dev)
{
unsigned char wbuf[8];
unsigned char rbuf[8];
gpio_set_value(dev->cs_gpio, 1);
gpio_set_value(dev->reset_gpio, 0);
mdelay(2);
gpio_set_value(dev->reset_gpio, 1);
mdelay(20);
gpio_set_value(dev->cs_gpio, 0);
usleep_range(100, 200);
ads1256_transfer(dev, ADS1256_CMD_REST);
mdelay(10);
while (gpio_get_value(dev->drdy_gpio))
;
wbuf[0] = ADS1256_CMD_SYNC;
wbuf[1] = ADS1256_CMD_WAKEUP;
ads1256_transfer_multibyte(dev, wbuf, rbuf, 2);
while (gpio_get_value(dev->drdy_gpio))
;
wbuf[0] = ADS1256_CMD_WREG | ADS1256_STATUS;
wbuf[1] = 3;
wbuf[2] = 0x04;
wbuf[3] = dev->channels[0];
wbuf[4] = ADS1256_GAIN_1;
wbuf[5] = ADS1256_DRATE_30000SPS;
ads1256_transfer_multibyte(dev, wbuf, rbuf, 6);
usleep_range(100, 200);
while (gpio_get_value(dev->drdy_gpio))
;
ads1256_transfer(dev, ADS1256_CMD_SELFCAL);
gpio_set_value(dev->cs_gpio, 1);
mdelay(100);
}
/*
* @description : spi驱动的probe函数,当驱动与
* 设备匹配以后此函数就会执行
* @param - spi : spi设备
*
*/
static int ads1256_probe(struct spi_device *spi)
{
int ret;
/* 1、构建设备号 */
if (ads1256dev.major)
{
ads1256dev.devid = MKDEV(ads1256dev.major, 0);
register_chrdev_region(ads1256dev.devid, ADS1256_CNT, ADS1256_NAME);
}
else
{
alloc_chrdev_region(&ads1256dev.devid, 0, ADS1256_CNT, ADS1256_NAME);
ads1256dev.major = MAJOR(ads1256dev.devid);
}
/* 2、注册设备 */
cdev_init(&ads1256dev.cdev, &ads1256_ops);
cdev_add(&ads1256dev.cdev, ads1256dev.devid, ADS1256_CNT);
/* 3、创建类 */
ads1256dev.class = class_create(THIS_MODULE, ADS1256_NAME);
if (IS_ERR(ads1256dev.class))
{
return PTR_ERR(ads1256dev.class);
}
/* 4、创建设备 */
ads1256dev.device = device_create(ads1256dev.class, NULL, ads1256dev.devid, NULL, ADS1256_NAME);
if (IS_ERR(ads1256dev.device))
{
return PTR_ERR(ads1256dev.device);
}
/*初始化spi_device */
spi->mode = SPI_MODE_1; /*MODE1,CPOL=0,CPHA=1*/
spi_setup(spi);
ads1256dev.private_data = spi; /* 设置私有数据 */
/* 设置ads1256所使用的GPIO */
/* 1、获取设备节点:ads1256 */
ads1256dev.nd = of_find_node_by_path("/soc/aips-bus@02000000/spba-bus@02000000/ecspi@02010000/ads1256@0");
if (ads1256dev.nd == NULL)
{
printk("ads1256 node not find!\r\n");
return -EINVAL;
}
else
{
printk("ads1256 node find!\r\n");
}
/* 2、 获取设备树中的gpio属性 */
ads1256dev.cs0_gpio = of_get_named_gpio(ads1256dev.nd, "cs0-gpio", 0);
ads1256dev.cs_gpio = of_get_named_gpio(ads1256dev.nd, "cs-gpio", 0);
ads1256dev.reset_gpio = of_get_named_gpio(ads1256dev.nd, "reset-gpio", 0);
ads1256dev.drdy_gpio = of_get_named_gpio(ads1256dev.nd, "drdy-gpio", 0);
if (ads1256dev.drdy_gpio < 0 || ads1256dev.reset_gpio < 0 || ads1256dev.cs_gpio < 0 || ads1256dev.cs0_gpio < 0)
{
printk("can't get all gpio");
return -EINVAL;
}
printk("ads1256 cs0-gpio num = %d\r\n", ads1256dev.cs0_gpio);
printk("ads1256 cs-gpio num = %d\r\n", ads1256dev.cs_gpio);
printk("ads1256 reset-gpio num = %d\r\n", ads1256dev.reset_gpio);
printk("ads1256 drdy-gpio num = %d\r\n", ads1256dev.drdy_gpio);
/* 3、配置输入输出
* 设置cs1-gpio为输出
* 设置reset-gpio为输出
* 设置drdy-gpio为输入 */
ret = gpio_direction_output(ads1256dev.cs0_gpio, 1);
ret = gpio_direction_output(ads1256dev.cs_gpio, 1);
ret = gpio_direction_output(ads1256dev.reset_gpio, 1);
ret = gpio_direction_input(ads1256dev.drdy_gpio);
if (ret < 0)
{
printk("can't set gpio!\r\n");
}
/* 初始化通道和延时 */
ads1256dev.delay_us = 100;
ads1256dev.channel_num = 1;
ads1256dev.channels[0] = ADS1256_MUXP_AIN0 | ADS1256_MUXN_AIN1;
/* 初始化ads1256内部寄存器 */
ads1256_reginit(&ads1256dev);
return 0;
}
/*
* @description : spi驱动的remove函数,移除spi驱动的时候此函数会执行
* @param - spi : spi设备
* @return : 0,成功;其他负值,失败
*/
static int ads1256_remove(struct spi_device *spi)
{
/* 注销设备的时候关闭片选 */
gpio_set_value(ads1256dev.cs_gpio, 1);
/* 删除设备 */
cdev_del(&ads1256dev.cdev);
unregister_chrdev_region(ads1256dev.devid, ADS1256_CNT);
/* 注销掉类和设备 */
device_destroy(ads1256dev.class, ads1256dev.devid);
class_destroy(ads1256dev.class);
return 0;
}
/*
* @description : 驱动入口函数
* @param : 无
* @return : 无
*/
static int __init ads1256_init(void)
{
return spi_register_driver(&ads1256_driver);
}
/*
* @description : 驱动出口函数
* @param : 无
* @return : 无
*/
static void __exit ads1256_exit(void)
{
spi_unregister_driver(&ads1256_driver);
}
module_init(ads1256_init);
module_exit(ads1256_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("liumingxin");
ads1256.h
#ifndef __ADS1256_H__
#define __ADS1256_H__
// define commands
#define ADS1256_CMD_WAKEUP 0x00 //完成SYNC和退出待机模式
#define ADS1256_CMD_RDATA 0x01 //读数据
#define ADS1256_CMD_RDATAC 0x03 //连续读数据
#define ADS1256_CMD_SDATAC 0x0f //停止连续读数据
#define ADS1256_CMD_RREG 0x10 //从寄存器度数据
#define ADS1256_CMD_WREG 0x50 //向寄存器写数据
#define ADS1256_CMD_SELFCAL 0xf0 //偏移和增益自动校准
#define ADS1256_CMD_SELFOCAL 0xf1 //偏移自动校准
#define ADS1256_CMD_SELFGCAL 0xf2 //增益自动校准
#define ADS1256_CMD_SYSOCAL 0xf3 //系统失调校准
#define ADS1256_CMD_SYSGCAL 0xf4 //系统增益校准
#define ADS1256_CMD_SYNC 0xfc //同步AD转换
#define ADS1256_CMD_STANDBY 0xfd //待机模式开始
#define ADS1256_CMD_REST 0xfe //复位
// define the ADS1256 register values
#define ADS1256_STATUS 0x00
#define ADS1256_MUX 0x01
#define ADS1256_ADCON 0x02
#define ADS1256_DRATE 0x03
#define ADS1256_IO 0x04
#define ADS1256_OFC0 0x05
#define ADS1256_OFC1 0x06
#define ADS1256_OFC2 0x07
#define ADS1256_FSC0 0x08
#define ADS1256_FSC1 0x09
#define ADS1256_FSC2 0x0A
// define multiplexer codes
#define ADS1256_MUXP_AIN0 0x00
#define ADS1256_MUXP_AIN1 0x10
#define ADS1256_MUXP_AIN2 0x20
#define ADS1256_MUXP_AIN3 0x30
#define ADS1256_MUXP_AIN4 0x40
#define ADS1256_MUXP_AIN5 0x50
#define ADS1256_MUXP_AIN6 0x60
#define ADS1256_MUXP_AIN7 0x70
#define ADS1256_MUXP_AINCOM 0x80
#define ADS1256_MUXN_AIN0 0x00
#define ADS1256_MUXN_AIN1 0x01
#define ADS1256_MUXN_AIN2 0x02
#define ADS1256_MUXN_AIN3 0x03
#define ADS1256_MUXN_AIN4 0x04
#define ADS1256_MUXN_AIN5 0x05
#define ADS1256_MUXN_AIN6 0x06
#define ADS1256_MUXN_AIN7 0x07
#define ADS1256_MUXN_AINCOM 0x08
// define gain codes
#define ADS1256_GAIN_1 0x00
#define ADS1256_GAIN_2 0x01
#define ADS1256_GAIN_4 0x02
#define ADS1256_GAIN_8 0x03
#define ADS1256_GAIN_16 0x04
#define ADS1256_GAIN_32 0x05
#define ADS1256_GAIN_64 0x06
//define drate codes
#define ADS1256_DRATE_30000SPS 0xF0
#define ADS1256_DRATE_15000SPS 0xE0
#define ADS1256_DRATE_7500SPS 0xD0
#define ADS1256_DRATE_3750SPS 0xC0
#define ADS1256_DRATE_2000SPS 0xB0
#define ADS1256_DRATE_1000SPS 0xA1
#define ADS1256_DRATE_500SPS 0x92
#define ADS1256_DRATE_100SPS 0x82
#define ADS1256_DRATE_60SPS 0x72
#define ADS1256_DRATE_50SPS 0x63
#define ADS1256_DRATE_30SPS 0x53
#define ADS1256_DRATE_25SPS 0x43
#define ADS1256_DRATE_15SPS 0x33
#define ADS1256_DRATE_10SPS 0x23
#define ADS1256_DRATE_5SPS 0x13
#define ADS1256_DRATE_2_5SPS 0x03
enum write_cmd
{
SET_CHANNELS = 0,
SET_FREQUENCY
};
#endif
Makefile
#先写生成的中间文件是什么,-m 的意思是把我们的驱动编译成模块
NAME = ads1256
obj-m += $(NAME).o
#KDIR: 内核源码所在路径
KDIR:=/home/lmx/workplace/IMX6ULL/linux-imx-4.1.15-2.1.0-g0423506-v2.2
#PWD: 获取当前目录的变量
PWD?=$(shell pwd)
#make 会进入内核源码的路径,然后把当前路径下的代码编译成模块
all:
make -C $(KDIR) M=$(PWD) modules
#-C表示 指定进入指定的目录即KERN,是内核源代码目录,调用该目录顶层下的Makefile,目标为modules。
#M=$(PWD)选项让该Makefile在构造modules目标之前返回到模块源代码目录并在当前目录生成obj-m指定的xxx.o目标模块。
clean:
rm $(NAME).o $(NAME).ko $(NAME).mod.o $(NAME).mod.c modules.order Module.symvers
注意编译前先设置好环境变量
export ARCH=arm
export CROSS_COMPILE=arm-linux-gnueabihf-
将编译好的模块 “ads1256.ko” 拷贝到NFS共享目录下。
开发板挂载NFS共享目录:
mount -t nfs -o nolock,nfsvers=3,vers=3 192.168.3.85:/home/lmx/workplace/share /mnt/nfs
取消挂载:
umount /mnt/nfs
使用 lsmod 命令发现已经加载了 icm20608 模块,先将模块注销,然后加载模块
rmmod icm20608
insmod ads1256.ko
ads1256.c
#include "unistd.h"
#include "sys/types.h"
#include "sys/stat.h"
#include "sys/ioctl.h"
#include
#include
#include
#include
#include "ads1256.h"
#include "stdlib.h"
#define REFERENCE_VOLTAGE 5
union Data
{
unsigned char data_8[4];
int data_32;
};
int ads1256_init(const char *filename)
{
int fd;
fd = open(filename, O_RDWR);
if (fd < 0)
{
return -1;
}
return fd;
}
void ads1256_deinit(int fd)
{
close(fd); /* 关闭文件 */
}
int ads1256_set_frequency(int fd, int frequency)
{
int ret = 0;
unsigned char buf[6];
buf[0] = SET_FREQUENCY;
buf[1] = 4;
buf[2] = frequency >> 24;
buf[3] = frequency >> 16;
buf[4] = frequency >> 8;
buf[5] = frequency & 0xFF;
ret = write(fd, buf, 6);
if (ret != 6)
{
return -1;
}
return 0;
}
int ads1256_set_channels(int fd, const unsigned char *channels, unsigned char num)
{
int ret = 0;
int i;
unsigned char buf[10];
if (num > 8)
{
return -1;
}
buf[0] = SET_CHANNELS;
buf[1] = num;
for (i = 0; i < num; i++)
{
buf[2 + i] = channels[i];
}
ret = write(fd, buf, num + 2);
if (ret != num + 2)
{
return -1;
}
return 0;
}
int ads1256_read_voltage(int fd, float *buf, int length)
{
union Data *databuf;
int ret;
int i;
databuf = malloc(sizeof(union Data) * length);
if (!databuf)
{
return -1;
}
ret = read(fd, databuf, length * 4);
for (i = 0; i < ret / 4; i++)
{
buf[i] = (float)(REFERENCE_VOLTAGE * databuf[i].data_32) / 0x800000;
}
free(databuf);
return ret / 4;
}
ads1256.h
#ifndef __ADS1256_H__
#define __ADS1256_H__
#ifdef __cplusplus
extern "C" {
#endif
#define ADS1256_MUXP_AIN0 0x00
#define ADS1256_MUXP_AIN1 0x10
#define ADS1256_MUXP_AIN2 0x20
#define ADS1256_MUXP_AIN3 0x30
#define ADS1256_MUXP_AIN4 0x40
#define ADS1256_MUXP_AIN5 0x50
#define ADS1256_MUXP_AIN6 0x60
#define ADS1256_MUXP_AIN7 0x70
#define ADS1256_MUXP_AINCOM 0x80
#define ADS1256_MUXN_AIN0 0x00
#define ADS1256_MUXN_AIN1 0x01
#define ADS1256_MUXN_AIN2 0x02
#define ADS1256_MUXN_AIN3 0x03
#define ADS1256_MUXN_AIN4 0x04
#define ADS1256_MUXN_AIN5 0x05
#define ADS1256_MUXN_AIN6 0x06
#define ADS1256_MUXN_AIN7 0x07
#define ADS1256_MUXN_AINCOM 0x08
enum write_cmd
{
SET_CHANNELS = 0,
SET_FREQUENCY
};
int ads1256_init(const char *filename);
void ads1256_deinit(int fd);
int ads1256_set_frequency(int fd, int frequency);
int ads1256_set_channels(int fd, const unsigned char *channels, unsigned char num);
int ads1256_read_voltage(int fd, float *buf, int length);
#ifdef __cplusplus
}
#endif
#endif // !__LIBADS1256_H__
编译成静态库:
arm-linux-guneabihf-gcc -c ads1256.c
arm-linux-gnueabihf-ar rcs libads1256.a ads1256.o