Taidou 1030、gpsセンサー、デフォルトのuartインターフェース、読み取りと書き込みのためのi2cインターフェースをサポートします。
ただし、td1030は、レジスタの概念を持つeeprom 24c02、温度および湿度センサーsth12などの通常のi2cデバイスを必要としません。
td1030は読み取りと書き込みのみが必要です。
.config - OpenWrt Configuration
> Kernel modules > I2C support ────────────────────────────────────────────────────────────────────────
┌────────────────────────────────────────── I2C support ───────────────────────────────────────────┐
│ Arrow keys navigate the menu. <Enter> selects submenus ---> (or empty submenus ----). │
│ Highlighted letters are hotkeys. Pressing <Y> includes, <N> excludes, <M> modularizes │
│ features. Press <Esc><Esc> to exit, <?> for Help, </> for Search. Legend: [*] built-in [ ] │
│ excluded <M> module < > module capable │
│ ┌──────────────────────────────────────────────────────────────────────────────────────────────┐ │
│ │ <*> kmod-i2c-core................................................ I2C support │ │
│ │ -*- kmod-i2c-algo-bit............................. I2C bit-banging interfaces │ │
│ │ < > kmod-i2c-algo-pca................................ I2C PCA 9564 interfaces │ │
│ │ < > kmod-i2c-algo-pcf................................ I2C PCF 8584 interfaces │ │
│ │ <*> kmod-i2c-gpio.................................. GPIO-based bitbanging I2C │ │
│ │ < > kmod-i2c-gpio-custom........................ Custom GPIO-based I2C device │ │
│ │ < > kmod-i2c-mt7628................................. MT7628/88 I2C Controller │ │
│ │ < > kmod-i2c-mux................................ I2C bus multiplexing support │ │
│ │ < > kmod-i2c-smbus........................... SMBus-specific protocols helper │ │
│ │ < > kmod-i2c-tiny-usb................................... I2C Tiny USB adaptor │ │
│ │ │ │
│ │ │ │
│ │ │ │
│ └──────────────────────────────────────────────────────────────────────────────────────────────┘ │
├──────────────────────────────────────────────────────────────────────────────────────────────────┤
│ <Select> < Exit > < Help > < Save > < Load > │
└──────────────────────────────────────────────────────────────────────────────────────────────────┘
-
読み取りには2つの方法があります:
1。ドライバーの書き込み、ロード後の読み取りと書き込み
2.ドライバーは不要、アプリケーション層で直接i2cバスの読み取りと書き込みを操作 -
td1030.cを書くドライバー
/*
* gps
*
* Written by: eric
*
*
*/
// #define DEBUG
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/string.h>
#include <linux/list.h>
#include <linux/sysfs.h>
#include <linux/ctype.h>
#include <linux/hwmon-sysfs.h>
#include <linux/uaccess.h>
#include <linux/delay.h>
// -------------------------------|-同步头--|--识别码--|---长度---|GGA|端口-|频率|保存|--校验---|
static const uint8_t gga_config[]={
0x23,0x3e,0x03,0x51,0x04,0x00,0x04,0x04,0x01,0x01,0x62,0x86};
static const uint8_t gsv_config[]={
0x23,0x3e,0x03,0x51,0x04,0x00,0x06,0x04,0x01,0x01,0x64,0x8e};
static const uint8_t rmc_config[]={
0x23, 0x3E, 0x03, 0x51,0x04, 0x00, 0x03, 0x04, 0x01, 0x01, 0x61, 0x82};
static const uint8_t gsa_config[]={
0x23, 0x3E, 0x03, 0x51,0x04, 0x00, 0x05, 0x04, 0x01, 0x01, 0x63, 0x8A};
static const uint8_t txt_config[]={
0x23, 0x3E, 0x03, 0x51,0x04, 0x00, 0x0D, 0x04, 0x01, 0x01, 0x6B, 0xAA};
// ACK:233E0101
// NACK:233E0102
static const uint8_t td1030_ack[]={
0x23,0x3E,0x01,0x01};
static const uint8_t td1030_nack[]={
0x23,0x3E,0x01,0x02};
/* Device registers */
#define TD1030_REG_CONFIG 0x00
#define TD1030_READ_LEN (256)
/**
* @brief hex数据转字符串
* @note
* @param data[]: hex数据
* @param data_len: hex数据长度
* @param *string: 输出字符串
* @param string_len: 输出字符串缓冲区长度
* @retval
*/
static int8_t hex2str(uint8_t data[], uint32_t data_len, uint8_t *string, uint32_t string_len)
{
uint32_t i;
uint8_t high_8bits_string = 0;
uint8_t low_8bits_string = 0;
if ( (2 * data_len) > string_len ) {
return -1;
}
for (i = 0; i < data_len; i++) {
/*parse high 8 bits value*/
high_8bits_string = data[i] / 16;
if (high_8bits_string <= 9) {
string[2 * i] = high_8bits_string + '0';
} else if (10 <= high_8bits_string && high_8bits_string <= 15) {
string[2 * i] = high_8bits_string - 10 + 'A';
} else {
return -2;
}
/*parse low 8 bits value*/
low_8bits_string = data[i] % 16;
if (low_8bits_string <= 9) {
string[2 * i + 1] = low_8bits_string + '0';
} else if (10 <= low_8bits_string && low_8bits_string <= 15) {
string[2 * i + 1] = low_8bits_string - 10 + 'A';
} else {
return -3;
}
}
return 0;
}
static void str_trim(char *src,char c)
{
int i,j;
for (i = 0, j = 0; src[i] != '\0'; i++)
{
if (src[i] != c)
{
src[j++] = src[i];
}
}
src[j] = '\0';
}
static void show_hex(struct device *dev,char *val,int len)
{
char hex[256]={
0};
memset(hex,0,256);
hex2str(val,len,hex,256);
dev_err(dev, "hex=%s\n",hex);
}
/*
* Generic counter attributes
*/
static ssize_t td1030_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct i2c_client *client = to_i2c_client(dev);
int rc=0;
uint8_t *val=NULL;
if (!(val = kmalloc(TD1030_READ_LEN, GFP_KERNEL)))
return -ENOMEM;
memset(val,0,TD1030_READ_LEN);
rc = i2c_master_recv(client, val, TD1030_READ_LEN-1);
if (rc < 0) {
dev_warn(dev, "i2c read data cmd failed\n");
goto _err;
}
str_trim(val,0xff);
// show_hex(dev,val,64);
// dev_dbg(dev, "read val=%s\n",val);
// char *p = strstr(val,'$');
// if(!p)
// goto _err;
rc = sprintf(buf,"%s",val);
kfree(val);
return rc;
// return copy_to_user(buf,val,strlen(val));
_err:
kfree(val);
return rc;
}
static ssize_t td1030_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct i2c_client *client = to_i2c_client(dev);
int rc;
uint8_t *set_buf=gga_config;
int set_len=sizeof(gga_config);
dev_dbg(dev, "td1030_store() called on %s\n", attr->attr.name);
dev_dbg(dev, "set command:%s.\n",buf);
if (!strcmp(buf,"gga")) {
set_buf=gga_config;
set_len=sizeof(gga_config);
}else if (!strcmp(buf,"gsv")){
set_buf=gsv_config;
set_len=sizeof(gsv_config);
}else if (!strcmp(buf,"rmc")){
set_buf=rmc_config;
set_len=sizeof(rmc_config);
}else if (!strcmp(buf,"gsa")){
set_buf=gsa_config;
set_len=sizeof(gsa_config);
}else if (!strcmp(buf,"txt")){
set_buf=txt_config;
set_len=sizeof(txt_config);
}else{
// show_hex(dev,buf,count);
return -EINVAL;
}
// 初始化
rc = i2c_master_send(client, set_buf, set_len);
if (rc < 0){
dev_warn(dev, "command failed.rc=%d\n", rc);
return -EIO;
}
// 申请接收区
uint8_t *val=NULL;
if (!(val = kmalloc(16, GFP_KERNEL)))
return -ENOMEM;
memset(val,0,16);
// 读取设置响应
rc = i2c_master_recv(client, val, 16);
if (rc < 0) {
dev_warn(dev, "i2c read data cmd failed\n");
goto _err;
}
str_trim(val,0xff);
show_hex(dev,val,16);
// 判断接收到的数据是否为ACK
if (memcmp(val,td1030_ack,sizeof(td1030_ack))){
dev_err(dev, "read cmd nack!\n");
goto _err;
}
dev_dbg(dev, "td1030 store ok\n");
kfree(val);
return count;
_err:
kfree(val);
return -1;
}
/*
* Simple register attributes
*/
static DEVICE_ATTR(get, S_IRUGO, td1030_show, NULL);
static DEVICE_ATTR(set, S_IWUSR, NULL, td1030_store);
static const struct attribute_group td1030_group = {
.attrs = (struct attribute *[]) {
&dev_attr_get.attr,
&dev_attr_set.attr,
NULL,
},
};
/*
* Called when a td1030 device is matched with this driver
*/
static int td1030_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
int rc;
if (!i2c_check_functionality(client->adapter,
I2C_FUNC_I2C)) {
dev_err(&client->dev, "i2c bus does not support the td1030\n");
rc = -ENODEV;
goto exit;
}
rc = sysfs_create_group(&client->dev.kobj, &td1030_group);
if (rc)
goto exit;
dev_dbg(&client->dev, "td1030 probe ok\n");
return 0;
exit:
return rc;
}
static int td1030_remove(struct i2c_client *client)
{
sysfs_remove_group(&client->dev.kobj, &td1030_group);
return 0;
}
static const struct i2c_device_id td1030_id[] = {
{
"td1030", 0 },
{
}
};
MODULE_DEVICE_TABLE(i2c, td1030_id);
static const struct of_device_id td1030_of_match[] = {
{
.compatible = "td1030", },
{
}
};
MODULE_DEVICE_TABLE(of, td1030_of_match);
static struct i2c_driver td1030_driver = {
.driver = {
.name = "td1030",
.of_match_table = td1030_of_match,
},
.probe = td1030_probe,
.remove = td1030_remove,
.id_table = td1030_id,
};
module_i2c_driver(td1030_driver);
MODULE_AUTHOR("[email protected]");
MODULE_DESCRIPTION("td1030 GPS driver");
MODULE_LICENSE("GPL");
- ロードドライブテスト
root@eric:/# ls
bin init overlay root td1030.ko var
dev lib proc sbin tmp www
etc mnt rom sys usr
root@eric:/#
...加载驱动
root@eric:/# insmod td1030.ko
root@eric:/# cd sys/bus/i2c/devices/0-0030/
root@eric:/sys/devices/platform/i2c-gpio-0/i2c-0/0-0030# ls
driver modalias of_node subsystem
get name set uevent
...设置gga i2c输出
root@eric:/sys/devices/platform/i2c-gpio-0/i2c-0/0-0030# echo -n gga > set
[ 3950.540987] td1030 0-0030: hex=233E0101020002000351586AFFFFFFFF
root@eric:/sys/devices/platform/i2c-gpio-0/i2c-0/0-0030#
...读取定位数据
root@eric:/sys/devices/platform/i2c-gpio-0/i2c-0/0-0030# cat get
$GNGGA,095516.00,3107.49910,N,12121.62030,E,1,17,0.66,71.0,M,9.8,M,,*4B
$GNGGA,095517.00,3107.49909,N,12121.62029,E,1,16,0.68,71.0,M,9.8,M,,*45
root@eric:/sys/devices/platform/i2c-gpio-0/i2c-0/0-0030#
- アプリケーション層は、i2cバスの読み取りおよび書き込みモードを直接呼び出します(次の章で紹介します)
mt7688プラットフォームのハードウェア制限により、一度に最大64バイトを読み取ることができますが、td1030は一度に少なくとも256バイトを読み取る必要があります。数回読み取ると、有効なデータが失われます。↩︎
シミュレートI2C設定https://blog.csdn.net/pyt1234567890/article/details/112990777 ↩︎