diff --git a/IMX6ULL/doc_pic/04_I2C/06_编写APP直接访问EEPROM.md b/IMX6ULL/doc_pic/04_I2C/06_编写APP直接访问EEPROM.md new file mode 100644 index 0000000..071883c --- /dev/null +++ b/IMX6ULL/doc_pic/04_I2C/06_编写APP直接访问EEPROM.md @@ -0,0 +1,143 @@ +## 编写APP直接访问EEPROM + +参考资料: + +* Linux驱动程序: `drivers/i2c/i2c-dev.c` +* I2C-Tools-4.2: `https://mirrors.edge.kernel.org/pub/software/utils/i2c-tools/` +* AT24cxx.pdf + +本节源码:GIT仓库中 + +* `doc_and_source_for_drivers\IMX6ULL\source\04_I2C\01_at24c02_test` +* `doc_and_source_for_drivers\STM32MP157\source\A7\04_I2C\01_at24c02_test` + +### 1. 硬件连接 + +* STM32MP157的I2C模块连接方法 + ![image-20210225170942275](pic/04_I2C/036_stm32mp157_with_i2c_module.png) + +* IMX6ULL的I2C模块连接方法 + ![image-20210225171500459](pic/04_I2C/037_imx6ull_with_i2c_module.png) + + + +### 2. AT24C02访问方法 + +#### 2.1 设备地址 + +从芯片手册上可以知道,AT24C02的设备地址跟它的A2、A1、A0引脚有关: + +![image-20210225173113723](pic/04_I2C/038_at24c02_device_address.png) + +打开I2C模块的原理图(这2个文件是一样的): + +* `STM32MP157\开发板配套资料\原理图\04_Extend_modules(外设模块)\eeprom.zip\i2c_eeprom_module_v1.0.pdf` +* `IMX6ULL\开发板配套资料\原理图\Extend_modules\eeprom.zip\i2c_eeprom_module_v1.0.pdf` +* 如下: + ![image-20210225173414072](pic/04_I2C/039_at24c02_sch.png) + +从原理图可知,A2A1A0都是0,所以AT24C02的设备地址是:0b1010000,即0x50。 + + + + + +#### 2.2 写数据 + +![image-20210225173850025](pic/04_I2C/040_at24c02_byte_write.png) + + + +#### 2.3 读数据 + +可以读1个字节,也可以连续读出多个字节。 +连续读多个字节时,芯片内部的地址会自动累加。 +当地址到达存储空间最后一个地址时,会从0开始。 + +![image-20210225173934939](pic/04_I2C/041_at24c02_byte_read.png) + +### 3. 使用I2C-Tools的函数编程 + + + +### 4. 编译 + +#### 4.1 在Ubuntu设置交叉编译工具链 + +* STM32MP157 + + ```shell + export ARCH=arm + export CROSS_COMPILE=arm-buildroot-linux-gnueabihf- + export PATH=$PATH:/home/book/100ask_stm32mp157_pro-sdk/ToolChain/arm-buildroot-linux-gnueabihf_sdk-buildroot/bin + ``` + +* IMX6ULL + + ```shell + export ARCH=arm + export CROSS_COMPILE=arm-linux-gnueabihf- + export PATH=$PATH:/home/book/100ask_imx6ull-sdk/ToolChain/gcc-linaro-6.2.1-2016.11-x86_64_arm-linux-gnueabihf/bin + ``` + + + +#### 4.2 使用I2C-Tools的源码 + +![image-20210225210415578](pic/04_I2C/044_use_file_from_i2c_tools.png) + +#### 4.3 编译 + +为IMX6ULL编译时,有如下错误: +![image-20210225205509383](pic/04_I2C/042_imx6ull_has_not_smbus.h.png) + +这是因为IMX6ULL的工具链自带的include目录中,没有smbus.h。 + +需要我们自己提供这个头文件,解决方法: + +* 提供头文件: + ![image-20210225205724354](pic/04_I2C/043_copy_include_from_i2c_tools.png) + +* 修改Makefile指定头文件目录 + + ```shell + all: + $(CROSS_COMPILE)gcc -I ./include -o at24c02_test at24c02_test.c i2cbusses.c smbus.c + + ``` + + + + + +### 4.4 上机测试 + +**以下命令在开发板中执行。** + +* 挂载NFS + + * vmware使用NAT(假设windowsIP为192.168.1.100) + + ```shell + [root@100ask:~]# mount -t nfs -o nolock,vers=3,port=2049,mountport=9999 + 192.168.1.100:/home/book/nfs_rootfs /mnt + ``` + + * vmware使用桥接,或者不使用vmware而是直接使用服务器:假设Ubuntu IP为192.168.1.137 + + ```shell + [root@100ask:~]# mount -t nfs -o nolock,vers=3 192.168.1.137:/home/book/nfs_rootfs /mnt + ``` + + + +* 复制、执行程序 + + ```shell + [root@100ask:~]# cp /mnt/at24c02_test /bin + [root@100ask:~]# at24c02_test 0 w www.100ask.net + [root@100ask:~]# at24c02_test 0 r +get data: www.100ask.net + ``` + + \ No newline at end of file diff --git a/IMX6ULL/doc_pic/04_I2C/pic/04_I2C/036_stm32mp157_with_i2c_module.png b/IMX6ULL/doc_pic/04_I2C/pic/04_I2C/036_stm32mp157_with_i2c_module.png new file mode 100644 index 0000000..6186d1a Binary files /dev/null and b/IMX6ULL/doc_pic/04_I2C/pic/04_I2C/036_stm32mp157_with_i2c_module.png differ diff --git a/IMX6ULL/doc_pic/04_I2C/pic/04_I2C/037_imx6ull_with_i2c_module.png b/IMX6ULL/doc_pic/04_I2C/pic/04_I2C/037_imx6ull_with_i2c_module.png new file mode 100644 index 0000000..0d396f0 Binary files /dev/null and b/IMX6ULL/doc_pic/04_I2C/pic/04_I2C/037_imx6ull_with_i2c_module.png differ diff --git a/IMX6ULL/doc_pic/04_I2C/pic/04_I2C/038_at24c02_device_address.png b/IMX6ULL/doc_pic/04_I2C/pic/04_I2C/038_at24c02_device_address.png new file mode 100644 index 0000000..780e47c Binary files /dev/null and b/IMX6ULL/doc_pic/04_I2C/pic/04_I2C/038_at24c02_device_address.png differ diff --git a/IMX6ULL/doc_pic/04_I2C/pic/04_I2C/039_at24c02_sch.png b/IMX6ULL/doc_pic/04_I2C/pic/04_I2C/039_at24c02_sch.png new file mode 100644 index 0000000..4a6813c Binary files /dev/null and b/IMX6ULL/doc_pic/04_I2C/pic/04_I2C/039_at24c02_sch.png differ diff --git a/IMX6ULL/doc_pic/04_I2C/pic/04_I2C/040_at24c02_byte_write.png b/IMX6ULL/doc_pic/04_I2C/pic/04_I2C/040_at24c02_byte_write.png new file mode 100644 index 0000000..938ae56 Binary files /dev/null and b/IMX6ULL/doc_pic/04_I2C/pic/04_I2C/040_at24c02_byte_write.png differ diff --git a/IMX6ULL/doc_pic/04_I2C/pic/04_I2C/041_at24c02_byte_read.png b/IMX6ULL/doc_pic/04_I2C/pic/04_I2C/041_at24c02_byte_read.png new file mode 100644 index 0000000..0d84d4f Binary files /dev/null and b/IMX6ULL/doc_pic/04_I2C/pic/04_I2C/041_at24c02_byte_read.png differ diff --git a/IMX6ULL/doc_pic/04_I2C/pic/04_I2C/042_imx6ull_has_not_smbus.h.png b/IMX6ULL/doc_pic/04_I2C/pic/04_I2C/042_imx6ull_has_not_smbus.h.png new file mode 100644 index 0000000..b40e7ef Binary files /dev/null and b/IMX6ULL/doc_pic/04_I2C/pic/04_I2C/042_imx6ull_has_not_smbus.h.png differ diff --git a/IMX6ULL/doc_pic/04_I2C/pic/04_I2C/043_copy_include_from_i2c_tools.png b/IMX6ULL/doc_pic/04_I2C/pic/04_I2C/043_copy_include_from_i2c_tools.png new file mode 100644 index 0000000..cbe0399 Binary files /dev/null and b/IMX6ULL/doc_pic/04_I2C/pic/04_I2C/043_copy_include_from_i2c_tools.png differ diff --git a/IMX6ULL/doc_pic/04_I2C/pic/04_I2C/044_use_file_from_i2c_tools.png b/IMX6ULL/doc_pic/04_I2C/pic/04_I2C/044_use_file_from_i2c_tools.png new file mode 100644 index 0000000..eeed67e Binary files /dev/null and b/IMX6ULL/doc_pic/04_I2C/pic/04_I2C/044_use_file_from_i2c_tools.png differ diff --git a/IMX6ULL/source/04_I2C/01_at24c02_test/Makefile b/IMX6ULL/source/04_I2C/01_at24c02_test/Makefile new file mode 100644 index 0000000..835a006 --- /dev/null +++ b/IMX6ULL/source/04_I2C/01_at24c02_test/Makefile @@ -0,0 +1,3 @@ +all: + $(CROSS_COMPILE)gcc -I ./include -o at24c02_test at24c02_test.c i2cbusses.c smbus.c + \ No newline at end of file diff --git a/IMX6ULL/source/04_I2C/01_at24c02_test/at24c02_test.c b/IMX6ULL/source/04_I2C/01_at24c02_test/at24c02_test.c new file mode 100644 index 0000000..04f3cf4 --- /dev/null +++ b/IMX6ULL/source/04_I2C/01_at24c02_test/at24c02_test.c @@ -0,0 +1,102 @@ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "i2cbusses.h" +#include + + +/* ./at24c02 w "100ask.taobao.com" + * ./at24c02 r + */ + +int main(int argc, char **argv) +{ + unsigned char dev_addr = 0x50; + unsigned char mem_addr = 0; + unsigned char buf[32]; + + int file; + char filename[20]; + unsigned char *str; + + int ret; + + struct timespec req; + + if (argc != 3 && argc != 4) + { + printf("Usage:\n"); + printf("write eeprom: %s w string\n", argv[0]); + printf("read eeprom: %s r\n", argv[0]); + return -1; + } + + file = open_i2c_dev(argv[1][0]-'0', filename, sizeof(filename), 0); + if (file < 0) + { + printf("can't open %s\n", filename); + return -1; + } + + if (set_slave_addr(file, dev_addr, 1)) + { + printf("can't set_slave_addr\n"); + return -1; + } + + if (argv[2][0] == 'w') + { + // write str: argv[3] + str = argv[3]; + + req.tv_sec = 0; + req.tv_nsec = 20000000; /* 20ms */ + + while (*str) + { + // mem_addr, *str + // mem_addr++, str++ + ret = i2c_smbus_write_byte_data(file, mem_addr, *str); + if (ret) + { + printf("i2c_smbus_write_byte_data err\n"); + return -1; + } + // wait tWR(10ms) + nanosleep(&req, NULL); + + mem_addr++; + str++; + } + ret = i2c_smbus_write_byte_data(file, mem_addr, 0); // string end char + if (ret) + { + printf("i2c_smbus_write_byte_data err\n"); + return -1; + } + } + else + { + // read + ret = i2c_smbus_read_i2c_block_data(file, mem_addr, sizeof(buf), buf); + if (ret < 0) + { + printf("i2c_smbus_read_i2c_block_data err\n"); + return -1; + } + + buf[31] = '\0'; + printf("get data: %s\n", buf); + } + + return 0; + +} + diff --git a/IMX6ULL/source/04_I2C/01_at24c02_test/i2cbusses.c b/IMX6ULL/source/04_I2C/01_at24c02_test/i2cbusses.c new file mode 100644 index 0000000..b4f00ae --- /dev/null +++ b/IMX6ULL/source/04_I2C/01_at24c02_test/i2cbusses.c @@ -0,0 +1,455 @@ +/* + i2cbusses: Print the installed i2c busses for both 2.4 and 2.6 kernels. + Part of user-space programs to access for I2C + devices. + Copyright (c) 1999-2003 Frodo Looijaard and + Mark D. Studebaker + Copyright (C) 2008-2012 Jean Delvare + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301 USA. +*/ + +/* For strdup and snprintf */ +#define _BSD_SOURCE 1 /* for glibc <= 2.19 */ +#define _DEFAULT_SOURCE 1 /* for glibc >= 2.19 */ + +#include +#include +#include /* for NAME_MAX */ +#include +#include +#include /* for strcasecmp() */ +#include +#include +#include +#include +#include +#include +#include +#include "i2cbusses.h" +#include +#include + +enum adt { adt_dummy, adt_isa, adt_i2c, adt_smbus, adt_unknown }; + +struct adap_type { + const char *funcs; + const char* algo; +}; + +static struct adap_type adap_types[5] = { + { .funcs = "dummy", + .algo = "Dummy bus", }, + { .funcs = "isa", + .algo = "ISA bus", }, + { .funcs = "i2c", + .algo = "I2C adapter", }, + { .funcs = "smbus", + .algo = "SMBus adapter", }, + { .funcs = "unknown", + .algo = "N/A", }, +}; + +static enum adt i2c_get_funcs(int i2cbus) +{ + unsigned long funcs; + int file; + char filename[20]; + enum adt ret; + + file = open_i2c_dev(i2cbus, filename, sizeof(filename), 1); + if (file < 0) + return adt_unknown; + + if (ioctl(file, I2C_FUNCS, &funcs) < 0) + ret = adt_unknown; + else if (funcs & I2C_FUNC_I2C) + ret = adt_i2c; + else if (funcs & (I2C_FUNC_SMBUS_BYTE | + I2C_FUNC_SMBUS_BYTE_DATA | + I2C_FUNC_SMBUS_WORD_DATA)) + ret = adt_smbus; + else + ret = adt_dummy; + + close(file); + return ret; +} + +/* Remove trailing spaces from a string + Return the new string length including the trailing NUL */ +static int rtrim(char *s) +{ + int i; + + for (i = strlen(s) - 1; i >= 0 && (s[i] == ' ' || s[i] == '\n'); i--) + s[i] = '\0'; + return i + 2; +} + +void free_adapters(struct i2c_adap *adapters) +{ + int i; + + for (i = 0; adapters[i].name; i++) + free(adapters[i].name); + free(adapters); +} + +/* We allocate space for the adapters in bunches. The last item is a + terminator, so here we start with room for 7 adapters, which should + be enough in most cases. If not, we allocate more later as needed. */ +#define BUNCH 8 + +/* n must match the size of adapters at calling time */ +static struct i2c_adap *more_adapters(struct i2c_adap *adapters, int n) +{ + struct i2c_adap *new_adapters; + + new_adapters = realloc(adapters, (n + BUNCH) * sizeof(struct i2c_adap)); + if (!new_adapters) { + free_adapters(adapters); + return NULL; + } + memset(new_adapters + n, 0, BUNCH * sizeof(struct i2c_adap)); + + return new_adapters; +} + +struct i2c_adap *gather_i2c_busses(void) +{ + char s[120]; + struct dirent *de, *dde; + DIR *dir, *ddir; + FILE *f; + char fstype[NAME_MAX], sysfs[NAME_MAX], n[NAME_MAX]; + int foundsysfs = 0; + int len, count = 0; + struct i2c_adap *adapters; + + adapters = calloc(BUNCH, sizeof(struct i2c_adap)); + if (!adapters) + return NULL; + + /* look in /proc/bus/i2c */ + if ((f = fopen("/proc/bus/i2c", "r"))) { + while (fgets(s, 120, f)) { + char *algo, *name, *type, *all; + int len_algo, len_name, len_type; + int i2cbus; + + algo = strrchr(s, '\t'); + *(algo++) = '\0'; + len_algo = rtrim(algo); + + name = strrchr(s, '\t'); + *(name++) = '\0'; + len_name = rtrim(name); + + type = strrchr(s, '\t'); + *(type++) = '\0'; + len_type = rtrim(type); + + sscanf(s, "i2c-%d", &i2cbus); + + if ((count + 1) % BUNCH == 0) { + /* We need more space */ + adapters = more_adapters(adapters, count + 1); + if (!adapters) + return NULL; + } + + all = malloc(len_name + len_type + len_algo); + if (all == NULL) { + free_adapters(adapters); + return NULL; + } + adapters[count].nr = i2cbus; + adapters[count].name = strcpy(all, name); + adapters[count].funcs = strcpy(all + len_name, type); + adapters[count].algo = strcpy(all + len_name + len_type, + algo); + count++; + } + fclose(f); + goto done; + } + + /* look in sysfs */ + /* First figure out where sysfs was mounted */ + if ((f = fopen("/proc/mounts", "r")) == NULL) { + goto done; + } + while (fgets(n, NAME_MAX, f)) { + sscanf(n, "%*[^ ] %[^ ] %[^ ] %*s\n", sysfs, fstype); + if (strcasecmp(fstype, "sysfs") == 0) { + foundsysfs++; + break; + } + } + fclose(f); + if (! foundsysfs) { + goto done; + } + + /* Bus numbers in i2c-adapter don't necessarily match those in + i2c-dev and what we really care about are the i2c-dev numbers. + Unfortunately the names are harder to get in i2c-dev */ + strcat(sysfs, "/class/i2c-dev"); + if(!(dir = opendir(sysfs))) + goto done; + /* go through the busses */ + while ((de = readdir(dir)) != NULL) { + if (!strcmp(de->d_name, ".")) + continue; + if (!strcmp(de->d_name, "..")) + continue; + + /* this should work for kernels 2.6.5 or higher and */ + /* is preferred because is unambiguous */ + len = snprintf(n, NAME_MAX, "%s/%s/name", sysfs, de->d_name); + if (len >= NAME_MAX) { + fprintf(stderr, "%s: path truncated\n", n); + continue; + } + f = fopen(n, "r"); + /* this seems to work for ISA */ + if(f == NULL) { + len = snprintf(n, NAME_MAX, "%s/%s/device/name", sysfs, + de->d_name); + if (len >= NAME_MAX) { + fprintf(stderr, "%s: path truncated\n", n); + continue; + } + f = fopen(n, "r"); + } + /* non-ISA is much harder */ + /* and this won't find the correct bus name if a driver + has more than one bus */ + if(f == NULL) { + len = snprintf(n, NAME_MAX, "%s/%s/device", sysfs, + de->d_name); + if (len >= NAME_MAX) { + fprintf(stderr, "%s: path truncated\n", n); + continue; + } + if(!(ddir = opendir(n))) + continue; + while ((dde = readdir(ddir)) != NULL) { + if (!strcmp(dde->d_name, ".")) + continue; + if (!strcmp(dde->d_name, "..")) + continue; + if ((!strncmp(dde->d_name, "i2c-", 4))) { + len = snprintf(n, NAME_MAX, + "%s/%s/device/%s/name", + sysfs, de->d_name, + dde->d_name); + if (len >= NAME_MAX) { + fprintf(stderr, + "%s: path truncated\n", + n); + continue; + } + if((f = fopen(n, "r"))) + goto found; + } + } + } + +found: + if (f != NULL) { + int i2cbus; + enum adt type; + char *px; + + px = fgets(s, 120, f); + fclose(f); + if (!px) { + fprintf(stderr, "%s: read error\n", n); + continue; + } + if ((px = strchr(s, '\n')) != NULL) + *px = 0; + if (!sscanf(de->d_name, "i2c-%d", &i2cbus)) + continue; + if (!strncmp(s, "ISA ", 4)) { + type = adt_isa; + } else { + /* Attempt to probe for adapter capabilities */ + type = i2c_get_funcs(i2cbus); + } + + if ((count + 1) % BUNCH == 0) { + /* We need more space */ + adapters = more_adapters(adapters, count + 1); + if (!adapters) + return NULL; + } + + adapters[count].nr = i2cbus; + adapters[count].name = strdup(s); + if (adapters[count].name == NULL) { + free_adapters(adapters); + return NULL; + } + adapters[count].funcs = adap_types[type].funcs; + adapters[count].algo = adap_types[type].algo; + count++; + } + } + closedir(dir); + +done: + return adapters; +} + +static int lookup_i2c_bus_by_name(const char *bus_name) +{ + struct i2c_adap *adapters; + int i, i2cbus = -1; + + adapters = gather_i2c_busses(); + if (adapters == NULL) { + fprintf(stderr, "Error: Out of memory!\n"); + return -3; + } + + /* Walk the list of i2c busses, looking for the one with the + right name */ + for (i = 0; adapters[i].name; i++) { + if (strcmp(adapters[i].name, bus_name) == 0) { + if (i2cbus >= 0) { + fprintf(stderr, + "Error: I2C bus name is not unique!\n"); + i2cbus = -4; + goto done; + } + i2cbus = adapters[i].nr; + } + } + + if (i2cbus == -1) + fprintf(stderr, "Error: I2C bus name doesn't match any " + "bus present!\n"); + +done: + free_adapters(adapters); + return i2cbus; +} + +/* + * Parse an I2CBUS command line argument and return the corresponding + * bus number, or a negative value if the bus is invalid. + */ +int lookup_i2c_bus(const char *i2cbus_arg) +{ + unsigned long i2cbus; + char *end; + + i2cbus = strtoul(i2cbus_arg, &end, 0); + if (*end || !*i2cbus_arg) { + /* Not a number, maybe a name? */ + return lookup_i2c_bus_by_name(i2cbus_arg); + } + if (i2cbus > 0xFFFFF) { + fprintf(stderr, "Error: I2C bus out of range!\n"); + return -2; + } + + return i2cbus; +} + +/* + * Parse a CHIP-ADDRESS command line argument and return the corresponding + * chip address, or a negative value if the address is invalid. + */ +int parse_i2c_address(const char *address_arg, int all_addrs) +{ + long address; + char *end; + long min_addr = 0x08; + long max_addr = 0x77; + + address = strtol(address_arg, &end, 0); + if (*end || !*address_arg) { + fprintf(stderr, "Error: Chip address is not a number!\n"); + return -1; + } + + if (all_addrs) { + min_addr = 0x00; + max_addr = 0x7f; + } + + if (address < min_addr || address > max_addr) { + fprintf(stderr, "Error: Chip address out of range " + "(0x%02lx-0x%02lx)!\n", min_addr, max_addr); + return -2; + } + + return address; +} + +int open_i2c_dev(int i2cbus, char *filename, size_t size, int quiet) +{ + int file, len; + + len = snprintf(filename, size, "/dev/i2c/%d", i2cbus); + if (len >= (int)size) { + fprintf(stderr, "%s: path truncated\n", filename); + return -EOVERFLOW; + } + file = open(filename, O_RDWR); + + if (file < 0 && (errno == ENOENT || errno == ENOTDIR)) { + len = snprintf(filename, size, "/dev/i2c-%d", i2cbus); + if (len >= (int)size) { + fprintf(stderr, "%s: path truncated\n", filename); + return -EOVERFLOW; + } + file = open(filename, O_RDWR); + } + + if (file < 0 && !quiet) { + if (errno == ENOENT) { + fprintf(stderr, "Error: Could not open file " + "`/dev/i2c-%d' or `/dev/i2c/%d': %s\n", + i2cbus, i2cbus, strerror(ENOENT)); + } else { + fprintf(stderr, "Error: Could not open file " + "`%s': %s\n", filename, strerror(errno)); + if (errno == EACCES) + fprintf(stderr, "Run as root?\n"); + } + } + + return file; +} + +int set_slave_addr(int file, int address, int force) +{ + /* With force, let the user read from/write to the registers + even when a driver is also running */ + if (ioctl(file, force ? I2C_SLAVE_FORCE : I2C_SLAVE, address) < 0) { + fprintf(stderr, + "Error: Could not set address to 0x%02x: %s\n", + address, strerror(errno)); + return -errno; + } + + return 0; +} diff --git a/IMX6ULL/source/04_I2C/01_at24c02_test/i2cbusses.h b/IMX6ULL/source/04_I2C/01_at24c02_test/i2cbusses.h new file mode 100644 index 0000000..a192c7f --- /dev/null +++ b/IMX6ULL/source/04_I2C/01_at24c02_test/i2cbusses.h @@ -0,0 +1,44 @@ +/* + i2cbusses.h - Part of the i2c-tools package + + Copyright (C) 2004-2010 Jean Delvare + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301 USA. +*/ + +#ifndef _I2CBUSSES_H +#define _I2CBUSSES_H + +#include + +struct i2c_adap { + int nr; + char *name; + const char *funcs; + const char *algo; +}; + +struct i2c_adap *gather_i2c_busses(void); +void free_adapters(struct i2c_adap *adapters); + +int lookup_i2c_bus(const char *i2cbus_arg); +int parse_i2c_address(const char *address_arg, int all_addrs); +int open_i2c_dev(int i2cbus, char *filename, size_t size, int quiet); +int set_slave_addr(int file, int address, int force); + +#define MISSING_FUNC_FMT "Error: Adapter does not have %s capability\n" + +#endif diff --git a/IMX6ULL/source/04_I2C/01_at24c02_test/include/i2c/smbus.h b/IMX6ULL/source/04_I2C/01_at24c02_test/include/i2c/smbus.h new file mode 100644 index 0000000..3003ed7 --- /dev/null +++ b/IMX6ULL/source/04_I2C/01_at24c02_test/include/i2c/smbus.h @@ -0,0 +1,52 @@ +/* + smbus.h - SMBus level access helper functions + + Copyright (C) 1995-1997 Simon G. Vogl + Copyright (C) 1998-1999 Frodo Looijaard + Copyright (C) 2012-2017 Jean Delvare + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. +*/ + +#ifndef LIB_I2C_SMBUS_H +#define LIB_I2C_SMBUS_H + +#define I2C_API_VERSION 0x100 + +#include +#include + +extern __s32 i2c_smbus_access(int file, char read_write, __u8 command, + int size, union i2c_smbus_data *data); + +extern __s32 i2c_smbus_write_quick(int file, __u8 value); +extern __s32 i2c_smbus_read_byte(int file); +extern __s32 i2c_smbus_write_byte(int file, __u8 value); +extern __s32 i2c_smbus_read_byte_data(int file, __u8 command); +extern __s32 i2c_smbus_write_byte_data(int file, __u8 command, __u8 value); +extern __s32 i2c_smbus_read_word_data(int file, __u8 command); +extern __s32 i2c_smbus_write_word_data(int file, __u8 command, __u16 value); +extern __s32 i2c_smbus_process_call(int file, __u8 command, __u16 value); + +/* Returns the number of read bytes */ +extern __s32 i2c_smbus_read_block_data(int file, __u8 command, __u8 *values); +extern __s32 i2c_smbus_write_block_data(int file, __u8 command, __u8 length, + const __u8 *values); + +/* Returns the number of read bytes */ +/* Until kernel 2.6.22, the length is hardcoded to 32 bytes. If you + ask for less than 32 bytes, your code will only work with kernels + 2.6.23 and later. */ +extern __s32 i2c_smbus_read_i2c_block_data(int file, __u8 command, __u8 length, + __u8 *values); +extern __s32 i2c_smbus_write_i2c_block_data(int file, __u8 command, __u8 length, + const __u8 *values); + +/* Returns the number of read bytes */ +extern __s32 i2c_smbus_block_process_call(int file, __u8 command, __u8 length, + __u8 *values); + +#endif /* LIB_I2C_SMBUS_H */ diff --git a/IMX6ULL/source/04_I2C/01_at24c02_test/smbus.c b/IMX6ULL/source/04_I2C/01_at24c02_test/smbus.c new file mode 100644 index 0000000..df5a5ad --- /dev/null +++ b/IMX6ULL/source/04_I2C/01_at24c02_test/smbus.c @@ -0,0 +1,214 @@ +/* + smbus.c - SMBus level access helper functions + + Copyright (C) 1995-1997 Simon G. Vogl + Copyright (C) 1998-1999 Frodo Looijaard + Copyright (C) 2012-2013 Jean Delvare + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. +*/ + +#include +#include +#include +#include +#include +#include +#include + +/* Compatibility defines */ +#ifndef I2C_SMBUS_I2C_BLOCK_BROKEN +#define I2C_SMBUS_I2C_BLOCK_BROKEN I2C_SMBUS_I2C_BLOCK_DATA +#endif +#ifndef I2C_FUNC_SMBUS_PEC +#define I2C_FUNC_SMBUS_PEC I2C_FUNC_SMBUS_HWPEC_CALC +#endif + +__s32 i2c_smbus_access(int file, char read_write, __u8 command, + int size, union i2c_smbus_data *data) +{ + struct i2c_smbus_ioctl_data args; + __s32 err; + + args.read_write = read_write; + args.command = command; + args.size = size; + args.data = data; + + err = ioctl(file, I2C_SMBUS, &args); + if (err == -1) + err = -errno; + return err; +} + + +__s32 i2c_smbus_write_quick(int file, __u8 value) +{ + return i2c_smbus_access(file, value, 0, I2C_SMBUS_QUICK, NULL); +} + +__s32 i2c_smbus_read_byte(int file) +{ + union i2c_smbus_data data; + int err; + + err = i2c_smbus_access(file, I2C_SMBUS_READ, 0, I2C_SMBUS_BYTE, &data); + if (err < 0) + return err; + + return 0x0FF & data.byte; +} + +__s32 i2c_smbus_write_byte(int file, __u8 value) +{ + return i2c_smbus_access(file, I2C_SMBUS_WRITE, value, + I2C_SMBUS_BYTE, NULL); +} + +__s32 i2c_smbus_read_byte_data(int file, __u8 command) +{ + union i2c_smbus_data data; + int err; + + err = i2c_smbus_access(file, I2C_SMBUS_READ, command, + I2C_SMBUS_BYTE_DATA, &data); + if (err < 0) + return err; + + return 0x0FF & data.byte; +} + +__s32 i2c_smbus_write_byte_data(int file, __u8 command, __u8 value) +{ + union i2c_smbus_data data; + data.byte = value; + return i2c_smbus_access(file, I2C_SMBUS_WRITE, command, + I2C_SMBUS_BYTE_DATA, &data); +} + +__s32 i2c_smbus_read_word_data(int file, __u8 command) +{ + union i2c_smbus_data data; + int err; + + err = i2c_smbus_access(file, I2C_SMBUS_READ, command, + I2C_SMBUS_WORD_DATA, &data); + if (err < 0) + return err; + + return 0x0FFFF & data.word; +} + +__s32 i2c_smbus_write_word_data(int file, __u8 command, __u16 value) +{ + union i2c_smbus_data data; + data.word = value; + return i2c_smbus_access(file, I2C_SMBUS_WRITE, command, + I2C_SMBUS_WORD_DATA, &data); +} + +__s32 i2c_smbus_process_call(int file, __u8 command, __u16 value) +{ + union i2c_smbus_data data; + data.word = value; + if (i2c_smbus_access(file, I2C_SMBUS_WRITE, command, + I2C_SMBUS_PROC_CALL, &data)) + return -1; + else + return 0x0FFFF & data.word; +} + +/* Returns the number of read bytes */ +__s32 i2c_smbus_read_block_data(int file, __u8 command, __u8 *values) +{ + union i2c_smbus_data data; + int i, err; + + err = i2c_smbus_access(file, I2C_SMBUS_READ, command, + I2C_SMBUS_BLOCK_DATA, &data); + if (err < 0) + return err; + + for (i = 1; i <= data.block[0]; i++) + values[i-1] = data.block[i]; + return data.block[0]; +} + +__s32 i2c_smbus_write_block_data(int file, __u8 command, __u8 length, + const __u8 *values) +{ + union i2c_smbus_data data; + int i; + if (length > I2C_SMBUS_BLOCK_MAX) + length = I2C_SMBUS_BLOCK_MAX; + for (i = 1; i <= length; i++) + data.block[i] = values[i-1]; + data.block[0] = length; + return i2c_smbus_access(file, I2C_SMBUS_WRITE, command, + I2C_SMBUS_BLOCK_DATA, &data); +} + +/* Returns the number of read bytes */ +/* Until kernel 2.6.22, the length is hardcoded to 32 bytes. If you + ask for less than 32 bytes, your code will only work with kernels + 2.6.23 and later. */ +__s32 i2c_smbus_read_i2c_block_data(int file, __u8 command, __u8 length, + __u8 *values) +{ + union i2c_smbus_data data; + int i, err; + + if (length > I2C_SMBUS_BLOCK_MAX) + length = I2C_SMBUS_BLOCK_MAX; + data.block[0] = length; + + err = i2c_smbus_access(file, I2C_SMBUS_READ, command, + length == 32 ? I2C_SMBUS_I2C_BLOCK_BROKEN : + I2C_SMBUS_I2C_BLOCK_DATA, &data); + if (err < 0) + return err; + + for (i = 1; i <= data.block[0]; i++) + values[i-1] = data.block[i]; + return data.block[0]; +} + +__s32 i2c_smbus_write_i2c_block_data(int file, __u8 command, __u8 length, + const __u8 *values) +{ + union i2c_smbus_data data; + int i; + if (length > I2C_SMBUS_BLOCK_MAX) + length = I2C_SMBUS_BLOCK_MAX; + for (i = 1; i <= length; i++) + data.block[i] = values[i-1]; + data.block[0] = length; + return i2c_smbus_access(file, I2C_SMBUS_WRITE, command, + I2C_SMBUS_I2C_BLOCK_BROKEN, &data); +} + +/* Returns the number of read bytes */ +__s32 i2c_smbus_block_process_call(int file, __u8 command, __u8 length, + __u8 *values) +{ + union i2c_smbus_data data; + int i, err; + + if (length > I2C_SMBUS_BLOCK_MAX) + length = I2C_SMBUS_BLOCK_MAX; + for (i = 1; i <= length; i++) + data.block[i] = values[i-1]; + data.block[0] = length; + + err = i2c_smbus_access(file, I2C_SMBUS_WRITE, command, + I2C_SMBUS_BLOCK_PROC_CALL, &data); + if (err < 0) + return err; + + for (i = 1; i <= data.block[0]; i++) + values[i-1] = data.block[i]; + return data.block[0]; +} diff --git a/IMX6ULL/开发板配套资料/datasheet/Base_board/100ask_imx6ull底板_规格书/I2C/AT24cxx.pdf b/IMX6ULL/开发板配套资料/datasheet/Base_board/100ask_imx6ull底板_规格书/I2C/AT24cxx.pdf new file mode 100644 index 0000000..7099ab2 Binary files /dev/null and b/IMX6ULL/开发板配套资料/datasheet/Base_board/100ask_imx6ull底板_规格书/I2C/AT24cxx.pdf differ diff --git a/README.md b/README.md index 7b5e3ef..c5b3f04 100644 --- a/README.md +++ b/README.md @@ -85,10 +85,10 @@ git clone https://e.coding.net/weidongshan/doc_and_source_for_drivers.git * 2021.02.25 发布"I2C系统": * 修改:03_SMBus协议,增加了I2C Block Read/Write +* 新增:05\_无需编写驱动直接访问设备\_I2C-Tools介绍 + * 新增:06_编写APP直接访问EEPROM - * 新增:05\_无需编写驱动直接访问设备\_I2C-Tools介绍 - - + ## 6. 联系方式 diff --git a/STM32MP157/doc_pic/04_I2C/03_SMBus协议.md b/STM32MP157/doc_pic/04_I2C/03_SMBus协议.md index 859315a..6fde6bf 100644 --- a/STM32MP157/doc_pic/04_I2C/03_SMBus协议.md +++ b/STM32MP157/doc_pic/04_I2C/03_SMBus协议.md @@ -221,7 +221,41 @@ Functionality flag: I2C_FUNC_SMBUS_WRITE_BLOCK_DATA -#### 2.11 SMBus Block Write - Block Read Process Call +#### 2.11 I2C Block Read + +在一般的I2C协议中,也可以连续读出多个字节。 +它跟`SMBus Block Read`的差别在于设备发出的第1个数据不是长度N,如下图所示: + +![image-20210225094024082](pic/04_I2C/033_i2c_block_read.png) + +I2C-tools中的函数:i2c_smbus_read_i2c_block_data()。 + +先发出`Command Code`(它一般表示芯片内部的寄存器地址),再发出1个字节的`Byte Conut`(表示后续要发出的数据字节数),最后发出全部数据。 + +```shell +Functionality flag: I2C_FUNC_SMBUS_READ_I2C_BLOCK +``` + + + +#### 2.12 I2C Block Write + +在一般的I2C协议中,也可以连续发出多个字节。 +它跟`SMBus Block Write`的差别在于发出的第1个数据不是长度N,如下图所示: + +![image-20210225094359443](pic/04_I2C/034_i2c_block_write.png) + +I2C-tools中的函数:i2c_smbus_write_i2c_block_data()。 + +先发出`Command Code`(它一般表示芯片内部的寄存器地址),再发出1个字节的`Byte Conut`(表示后续要发出的数据字节数),最后发出全部数据。 + +```shell +Functionality flag: I2C_FUNC_SMBUS_WRITE_I2C_BLOCK +``` + + + +#### 2.13 SMBus Block Write - Block Read Process Call ![image-20210224112940865](pic/04_I2C/028_smbus_block_write_block_read_process_call.png)先写一块数据,再读一块数据。 @@ -231,7 +265,7 @@ Functionality flag: I2C_FUNC_SMBUS_BLOCK_PROC_CALL -#### 2.12 Packet Error Checking (PEC) +#### 2.14 Packet Error Checking (PEC) PEC是一种错误校验码,如果使用PEC,那么在P信号之前,数据发送方要发送一个字节的PEC码(它是CRC-8码)。 diff --git a/STM32MP157/doc_pic/04_I2C/06_编写APP直接访问EEPROM.md b/STM32MP157/doc_pic/04_I2C/06_编写APP直接访问EEPROM.md new file mode 100644 index 0000000..071883c --- /dev/null +++ b/STM32MP157/doc_pic/04_I2C/06_编写APP直接访问EEPROM.md @@ -0,0 +1,143 @@ +## 编写APP直接访问EEPROM + +参考资料: + +* Linux驱动程序: `drivers/i2c/i2c-dev.c` +* I2C-Tools-4.2: `https://mirrors.edge.kernel.org/pub/software/utils/i2c-tools/` +* AT24cxx.pdf + +本节源码:GIT仓库中 + +* `doc_and_source_for_drivers\IMX6ULL\source\04_I2C\01_at24c02_test` +* `doc_and_source_for_drivers\STM32MP157\source\A7\04_I2C\01_at24c02_test` + +### 1. 硬件连接 + +* STM32MP157的I2C模块连接方法 + ![image-20210225170942275](pic/04_I2C/036_stm32mp157_with_i2c_module.png) + +* IMX6ULL的I2C模块连接方法 + ![image-20210225171500459](pic/04_I2C/037_imx6ull_with_i2c_module.png) + + + +### 2. AT24C02访问方法 + +#### 2.1 设备地址 + +从芯片手册上可以知道,AT24C02的设备地址跟它的A2、A1、A0引脚有关: + +![image-20210225173113723](pic/04_I2C/038_at24c02_device_address.png) + +打开I2C模块的原理图(这2个文件是一样的): + +* `STM32MP157\开发板配套资料\原理图\04_Extend_modules(外设模块)\eeprom.zip\i2c_eeprom_module_v1.0.pdf` +* `IMX6ULL\开发板配套资料\原理图\Extend_modules\eeprom.zip\i2c_eeprom_module_v1.0.pdf` +* 如下: + ![image-20210225173414072](pic/04_I2C/039_at24c02_sch.png) + +从原理图可知,A2A1A0都是0,所以AT24C02的设备地址是:0b1010000,即0x50。 + + + + + +#### 2.2 写数据 + +![image-20210225173850025](pic/04_I2C/040_at24c02_byte_write.png) + + + +#### 2.3 读数据 + +可以读1个字节,也可以连续读出多个字节。 +连续读多个字节时,芯片内部的地址会自动累加。 +当地址到达存储空间最后一个地址时,会从0开始。 + +![image-20210225173934939](pic/04_I2C/041_at24c02_byte_read.png) + +### 3. 使用I2C-Tools的函数编程 + + + +### 4. 编译 + +#### 4.1 在Ubuntu设置交叉编译工具链 + +* STM32MP157 + + ```shell + export ARCH=arm + export CROSS_COMPILE=arm-buildroot-linux-gnueabihf- + export PATH=$PATH:/home/book/100ask_stm32mp157_pro-sdk/ToolChain/arm-buildroot-linux-gnueabihf_sdk-buildroot/bin + ``` + +* IMX6ULL + + ```shell + export ARCH=arm + export CROSS_COMPILE=arm-linux-gnueabihf- + export PATH=$PATH:/home/book/100ask_imx6ull-sdk/ToolChain/gcc-linaro-6.2.1-2016.11-x86_64_arm-linux-gnueabihf/bin + ``` + + + +#### 4.2 使用I2C-Tools的源码 + +![image-20210225210415578](pic/04_I2C/044_use_file_from_i2c_tools.png) + +#### 4.3 编译 + +为IMX6ULL编译时,有如下错误: +![image-20210225205509383](pic/04_I2C/042_imx6ull_has_not_smbus.h.png) + +这是因为IMX6ULL的工具链自带的include目录中,没有smbus.h。 + +需要我们自己提供这个头文件,解决方法: + +* 提供头文件: + ![image-20210225205724354](pic/04_I2C/043_copy_include_from_i2c_tools.png) + +* 修改Makefile指定头文件目录 + + ```shell + all: + $(CROSS_COMPILE)gcc -I ./include -o at24c02_test at24c02_test.c i2cbusses.c smbus.c + + ``` + + + + + +### 4.4 上机测试 + +**以下命令在开发板中执行。** + +* 挂载NFS + + * vmware使用NAT(假设windowsIP为192.168.1.100) + + ```shell + [root@100ask:~]# mount -t nfs -o nolock,vers=3,port=2049,mountport=9999 + 192.168.1.100:/home/book/nfs_rootfs /mnt + ``` + + * vmware使用桥接,或者不使用vmware而是直接使用服务器:假设Ubuntu IP为192.168.1.137 + + ```shell + [root@100ask:~]# mount -t nfs -o nolock,vers=3 192.168.1.137:/home/book/nfs_rootfs /mnt + ``` + + + +* 复制、执行程序 + + ```shell + [root@100ask:~]# cp /mnt/at24c02_test /bin + [root@100ask:~]# at24c02_test 0 w www.100ask.net + [root@100ask:~]# at24c02_test 0 r +get data: www.100ask.net + ``` + + \ No newline at end of file diff --git a/STM32MP157/doc_pic/04_I2C/pic/04_I2C/036_stm32mp157_with_i2c_module.png b/STM32MP157/doc_pic/04_I2C/pic/04_I2C/036_stm32mp157_with_i2c_module.png new file mode 100644 index 0000000..6186d1a Binary files /dev/null and b/STM32MP157/doc_pic/04_I2C/pic/04_I2C/036_stm32mp157_with_i2c_module.png differ diff --git a/STM32MP157/doc_pic/04_I2C/pic/04_I2C/037_imx6ull_with_i2c_module.png b/STM32MP157/doc_pic/04_I2C/pic/04_I2C/037_imx6ull_with_i2c_module.png new file mode 100644 index 0000000..0d396f0 Binary files /dev/null and b/STM32MP157/doc_pic/04_I2C/pic/04_I2C/037_imx6ull_with_i2c_module.png differ diff --git a/STM32MP157/doc_pic/04_I2C/pic/04_I2C/038_at24c02_device_address.png b/STM32MP157/doc_pic/04_I2C/pic/04_I2C/038_at24c02_device_address.png new file mode 100644 index 0000000..780e47c Binary files /dev/null and b/STM32MP157/doc_pic/04_I2C/pic/04_I2C/038_at24c02_device_address.png differ diff --git a/STM32MP157/doc_pic/04_I2C/pic/04_I2C/039_at24c02_sch.png b/STM32MP157/doc_pic/04_I2C/pic/04_I2C/039_at24c02_sch.png new file mode 100644 index 0000000..4a6813c Binary files /dev/null and b/STM32MP157/doc_pic/04_I2C/pic/04_I2C/039_at24c02_sch.png differ diff --git a/STM32MP157/doc_pic/04_I2C/pic/04_I2C/040_at24c02_byte_write.png b/STM32MP157/doc_pic/04_I2C/pic/04_I2C/040_at24c02_byte_write.png new file mode 100644 index 0000000..938ae56 Binary files /dev/null and b/STM32MP157/doc_pic/04_I2C/pic/04_I2C/040_at24c02_byte_write.png differ diff --git a/STM32MP157/doc_pic/04_I2C/pic/04_I2C/041_at24c02_byte_read.png b/STM32MP157/doc_pic/04_I2C/pic/04_I2C/041_at24c02_byte_read.png new file mode 100644 index 0000000..0d84d4f Binary files /dev/null and b/STM32MP157/doc_pic/04_I2C/pic/04_I2C/041_at24c02_byte_read.png differ diff --git a/STM32MP157/doc_pic/04_I2C/pic/04_I2C/042_imx6ull_has_not_smbus.h.png b/STM32MP157/doc_pic/04_I2C/pic/04_I2C/042_imx6ull_has_not_smbus.h.png new file mode 100644 index 0000000..b40e7ef Binary files /dev/null and b/STM32MP157/doc_pic/04_I2C/pic/04_I2C/042_imx6ull_has_not_smbus.h.png differ diff --git a/STM32MP157/doc_pic/04_I2C/pic/04_I2C/043_copy_include_from_i2c_tools.png b/STM32MP157/doc_pic/04_I2C/pic/04_I2C/043_copy_include_from_i2c_tools.png new file mode 100644 index 0000000..cbe0399 Binary files /dev/null and b/STM32MP157/doc_pic/04_I2C/pic/04_I2C/043_copy_include_from_i2c_tools.png differ diff --git a/STM32MP157/doc_pic/04_I2C/pic/04_I2C/044_use_file_from_i2c_tools.png b/STM32MP157/doc_pic/04_I2C/pic/04_I2C/044_use_file_from_i2c_tools.png new file mode 100644 index 0000000..eeed67e Binary files /dev/null and b/STM32MP157/doc_pic/04_I2C/pic/04_I2C/044_use_file_from_i2c_tools.png differ diff --git a/STM32MP157/source/A7/04_I2C/01_at24c02_test/Makefile b/STM32MP157/source/A7/04_I2C/01_at24c02_test/Makefile new file mode 100644 index 0000000..835a006 --- /dev/null +++ b/STM32MP157/source/A7/04_I2C/01_at24c02_test/Makefile @@ -0,0 +1,3 @@ +all: + $(CROSS_COMPILE)gcc -I ./include -o at24c02_test at24c02_test.c i2cbusses.c smbus.c + \ No newline at end of file diff --git a/STM32MP157/source/A7/04_I2C/01_at24c02_test/at24c02_test.c b/STM32MP157/source/A7/04_I2C/01_at24c02_test/at24c02_test.c new file mode 100644 index 0000000..04f3cf4 --- /dev/null +++ b/STM32MP157/source/A7/04_I2C/01_at24c02_test/at24c02_test.c @@ -0,0 +1,102 @@ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "i2cbusses.h" +#include + + +/* ./at24c02 w "100ask.taobao.com" + * ./at24c02 r + */ + +int main(int argc, char **argv) +{ + unsigned char dev_addr = 0x50; + unsigned char mem_addr = 0; + unsigned char buf[32]; + + int file; + char filename[20]; + unsigned char *str; + + int ret; + + struct timespec req; + + if (argc != 3 && argc != 4) + { + printf("Usage:\n"); + printf("write eeprom: %s w string\n", argv[0]); + printf("read eeprom: %s r\n", argv[0]); + return -1; + } + + file = open_i2c_dev(argv[1][0]-'0', filename, sizeof(filename), 0); + if (file < 0) + { + printf("can't open %s\n", filename); + return -1; + } + + if (set_slave_addr(file, dev_addr, 1)) + { + printf("can't set_slave_addr\n"); + return -1; + } + + if (argv[2][0] == 'w') + { + // write str: argv[3] + str = argv[3]; + + req.tv_sec = 0; + req.tv_nsec = 20000000; /* 20ms */ + + while (*str) + { + // mem_addr, *str + // mem_addr++, str++ + ret = i2c_smbus_write_byte_data(file, mem_addr, *str); + if (ret) + { + printf("i2c_smbus_write_byte_data err\n"); + return -1; + } + // wait tWR(10ms) + nanosleep(&req, NULL); + + mem_addr++; + str++; + } + ret = i2c_smbus_write_byte_data(file, mem_addr, 0); // string end char + if (ret) + { + printf("i2c_smbus_write_byte_data err\n"); + return -1; + } + } + else + { + // read + ret = i2c_smbus_read_i2c_block_data(file, mem_addr, sizeof(buf), buf); + if (ret < 0) + { + printf("i2c_smbus_read_i2c_block_data err\n"); + return -1; + } + + buf[31] = '\0'; + printf("get data: %s\n", buf); + } + + return 0; + +} + diff --git a/STM32MP157/source/A7/04_I2C/01_at24c02_test/i2cbusses.c b/STM32MP157/source/A7/04_I2C/01_at24c02_test/i2cbusses.c new file mode 100644 index 0000000..b4f00ae --- /dev/null +++ b/STM32MP157/source/A7/04_I2C/01_at24c02_test/i2cbusses.c @@ -0,0 +1,455 @@ +/* + i2cbusses: Print the installed i2c busses for both 2.4 and 2.6 kernels. + Part of user-space programs to access for I2C + devices. + Copyright (c) 1999-2003 Frodo Looijaard and + Mark D. Studebaker + Copyright (C) 2008-2012 Jean Delvare + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301 USA. +*/ + +/* For strdup and snprintf */ +#define _BSD_SOURCE 1 /* for glibc <= 2.19 */ +#define _DEFAULT_SOURCE 1 /* for glibc >= 2.19 */ + +#include +#include +#include /* for NAME_MAX */ +#include +#include +#include /* for strcasecmp() */ +#include +#include +#include +#include +#include +#include +#include +#include "i2cbusses.h" +#include +#include + +enum adt { adt_dummy, adt_isa, adt_i2c, adt_smbus, adt_unknown }; + +struct adap_type { + const char *funcs; + const char* algo; +}; + +static struct adap_type adap_types[5] = { + { .funcs = "dummy", + .algo = "Dummy bus", }, + { .funcs = "isa", + .algo = "ISA bus", }, + { .funcs = "i2c", + .algo = "I2C adapter", }, + { .funcs = "smbus", + .algo = "SMBus adapter", }, + { .funcs = "unknown", + .algo = "N/A", }, +}; + +static enum adt i2c_get_funcs(int i2cbus) +{ + unsigned long funcs; + int file; + char filename[20]; + enum adt ret; + + file = open_i2c_dev(i2cbus, filename, sizeof(filename), 1); + if (file < 0) + return adt_unknown; + + if (ioctl(file, I2C_FUNCS, &funcs) < 0) + ret = adt_unknown; + else if (funcs & I2C_FUNC_I2C) + ret = adt_i2c; + else if (funcs & (I2C_FUNC_SMBUS_BYTE | + I2C_FUNC_SMBUS_BYTE_DATA | + I2C_FUNC_SMBUS_WORD_DATA)) + ret = adt_smbus; + else + ret = adt_dummy; + + close(file); + return ret; +} + +/* Remove trailing spaces from a string + Return the new string length including the trailing NUL */ +static int rtrim(char *s) +{ + int i; + + for (i = strlen(s) - 1; i >= 0 && (s[i] == ' ' || s[i] == '\n'); i--) + s[i] = '\0'; + return i + 2; +} + +void free_adapters(struct i2c_adap *adapters) +{ + int i; + + for (i = 0; adapters[i].name; i++) + free(adapters[i].name); + free(adapters); +} + +/* We allocate space for the adapters in bunches. The last item is a + terminator, so here we start with room for 7 adapters, which should + be enough in most cases. If not, we allocate more later as needed. */ +#define BUNCH 8 + +/* n must match the size of adapters at calling time */ +static struct i2c_adap *more_adapters(struct i2c_adap *adapters, int n) +{ + struct i2c_adap *new_adapters; + + new_adapters = realloc(adapters, (n + BUNCH) * sizeof(struct i2c_adap)); + if (!new_adapters) { + free_adapters(adapters); + return NULL; + } + memset(new_adapters + n, 0, BUNCH * sizeof(struct i2c_adap)); + + return new_adapters; +} + +struct i2c_adap *gather_i2c_busses(void) +{ + char s[120]; + struct dirent *de, *dde; + DIR *dir, *ddir; + FILE *f; + char fstype[NAME_MAX], sysfs[NAME_MAX], n[NAME_MAX]; + int foundsysfs = 0; + int len, count = 0; + struct i2c_adap *adapters; + + adapters = calloc(BUNCH, sizeof(struct i2c_adap)); + if (!adapters) + return NULL; + + /* look in /proc/bus/i2c */ + if ((f = fopen("/proc/bus/i2c", "r"))) { + while (fgets(s, 120, f)) { + char *algo, *name, *type, *all; + int len_algo, len_name, len_type; + int i2cbus; + + algo = strrchr(s, '\t'); + *(algo++) = '\0'; + len_algo = rtrim(algo); + + name = strrchr(s, '\t'); + *(name++) = '\0'; + len_name = rtrim(name); + + type = strrchr(s, '\t'); + *(type++) = '\0'; + len_type = rtrim(type); + + sscanf(s, "i2c-%d", &i2cbus); + + if ((count + 1) % BUNCH == 0) { + /* We need more space */ + adapters = more_adapters(adapters, count + 1); + if (!adapters) + return NULL; + } + + all = malloc(len_name + len_type + len_algo); + if (all == NULL) { + free_adapters(adapters); + return NULL; + } + adapters[count].nr = i2cbus; + adapters[count].name = strcpy(all, name); + adapters[count].funcs = strcpy(all + len_name, type); + adapters[count].algo = strcpy(all + len_name + len_type, + algo); + count++; + } + fclose(f); + goto done; + } + + /* look in sysfs */ + /* First figure out where sysfs was mounted */ + if ((f = fopen("/proc/mounts", "r")) == NULL) { + goto done; + } + while (fgets(n, NAME_MAX, f)) { + sscanf(n, "%*[^ ] %[^ ] %[^ ] %*s\n", sysfs, fstype); + if (strcasecmp(fstype, "sysfs") == 0) { + foundsysfs++; + break; + } + } + fclose(f); + if (! foundsysfs) { + goto done; + } + + /* Bus numbers in i2c-adapter don't necessarily match those in + i2c-dev and what we really care about are the i2c-dev numbers. + Unfortunately the names are harder to get in i2c-dev */ + strcat(sysfs, "/class/i2c-dev"); + if(!(dir = opendir(sysfs))) + goto done; + /* go through the busses */ + while ((de = readdir(dir)) != NULL) { + if (!strcmp(de->d_name, ".")) + continue; + if (!strcmp(de->d_name, "..")) + continue; + + /* this should work for kernels 2.6.5 or higher and */ + /* is preferred because is unambiguous */ + len = snprintf(n, NAME_MAX, "%s/%s/name", sysfs, de->d_name); + if (len >= NAME_MAX) { + fprintf(stderr, "%s: path truncated\n", n); + continue; + } + f = fopen(n, "r"); + /* this seems to work for ISA */ + if(f == NULL) { + len = snprintf(n, NAME_MAX, "%s/%s/device/name", sysfs, + de->d_name); + if (len >= NAME_MAX) { + fprintf(stderr, "%s: path truncated\n", n); + continue; + } + f = fopen(n, "r"); + } + /* non-ISA is much harder */ + /* and this won't find the correct bus name if a driver + has more than one bus */ + if(f == NULL) { + len = snprintf(n, NAME_MAX, "%s/%s/device", sysfs, + de->d_name); + if (len >= NAME_MAX) { + fprintf(stderr, "%s: path truncated\n", n); + continue; + } + if(!(ddir = opendir(n))) + continue; + while ((dde = readdir(ddir)) != NULL) { + if (!strcmp(dde->d_name, ".")) + continue; + if (!strcmp(dde->d_name, "..")) + continue; + if ((!strncmp(dde->d_name, "i2c-", 4))) { + len = snprintf(n, NAME_MAX, + "%s/%s/device/%s/name", + sysfs, de->d_name, + dde->d_name); + if (len >= NAME_MAX) { + fprintf(stderr, + "%s: path truncated\n", + n); + continue; + } + if((f = fopen(n, "r"))) + goto found; + } + } + } + +found: + if (f != NULL) { + int i2cbus; + enum adt type; + char *px; + + px = fgets(s, 120, f); + fclose(f); + if (!px) { + fprintf(stderr, "%s: read error\n", n); + continue; + } + if ((px = strchr(s, '\n')) != NULL) + *px = 0; + if (!sscanf(de->d_name, "i2c-%d", &i2cbus)) + continue; + if (!strncmp(s, "ISA ", 4)) { + type = adt_isa; + } else { + /* Attempt to probe for adapter capabilities */ + type = i2c_get_funcs(i2cbus); + } + + if ((count + 1) % BUNCH == 0) { + /* We need more space */ + adapters = more_adapters(adapters, count + 1); + if (!adapters) + return NULL; + } + + adapters[count].nr = i2cbus; + adapters[count].name = strdup(s); + if (adapters[count].name == NULL) { + free_adapters(adapters); + return NULL; + } + adapters[count].funcs = adap_types[type].funcs; + adapters[count].algo = adap_types[type].algo; + count++; + } + } + closedir(dir); + +done: + return adapters; +} + +static int lookup_i2c_bus_by_name(const char *bus_name) +{ + struct i2c_adap *adapters; + int i, i2cbus = -1; + + adapters = gather_i2c_busses(); + if (adapters == NULL) { + fprintf(stderr, "Error: Out of memory!\n"); + return -3; + } + + /* Walk the list of i2c busses, looking for the one with the + right name */ + for (i = 0; adapters[i].name; i++) { + if (strcmp(adapters[i].name, bus_name) == 0) { + if (i2cbus >= 0) { + fprintf(stderr, + "Error: I2C bus name is not unique!\n"); + i2cbus = -4; + goto done; + } + i2cbus = adapters[i].nr; + } + } + + if (i2cbus == -1) + fprintf(stderr, "Error: I2C bus name doesn't match any " + "bus present!\n"); + +done: + free_adapters(adapters); + return i2cbus; +} + +/* + * Parse an I2CBUS command line argument and return the corresponding + * bus number, or a negative value if the bus is invalid. + */ +int lookup_i2c_bus(const char *i2cbus_arg) +{ + unsigned long i2cbus; + char *end; + + i2cbus = strtoul(i2cbus_arg, &end, 0); + if (*end || !*i2cbus_arg) { + /* Not a number, maybe a name? */ + return lookup_i2c_bus_by_name(i2cbus_arg); + } + if (i2cbus > 0xFFFFF) { + fprintf(stderr, "Error: I2C bus out of range!\n"); + return -2; + } + + return i2cbus; +} + +/* + * Parse a CHIP-ADDRESS command line argument and return the corresponding + * chip address, or a negative value if the address is invalid. + */ +int parse_i2c_address(const char *address_arg, int all_addrs) +{ + long address; + char *end; + long min_addr = 0x08; + long max_addr = 0x77; + + address = strtol(address_arg, &end, 0); + if (*end || !*address_arg) { + fprintf(stderr, "Error: Chip address is not a number!\n"); + return -1; + } + + if (all_addrs) { + min_addr = 0x00; + max_addr = 0x7f; + } + + if (address < min_addr || address > max_addr) { + fprintf(stderr, "Error: Chip address out of range " + "(0x%02lx-0x%02lx)!\n", min_addr, max_addr); + return -2; + } + + return address; +} + +int open_i2c_dev(int i2cbus, char *filename, size_t size, int quiet) +{ + int file, len; + + len = snprintf(filename, size, "/dev/i2c/%d", i2cbus); + if (len >= (int)size) { + fprintf(stderr, "%s: path truncated\n", filename); + return -EOVERFLOW; + } + file = open(filename, O_RDWR); + + if (file < 0 && (errno == ENOENT || errno == ENOTDIR)) { + len = snprintf(filename, size, "/dev/i2c-%d", i2cbus); + if (len >= (int)size) { + fprintf(stderr, "%s: path truncated\n", filename); + return -EOVERFLOW; + } + file = open(filename, O_RDWR); + } + + if (file < 0 && !quiet) { + if (errno == ENOENT) { + fprintf(stderr, "Error: Could not open file " + "`/dev/i2c-%d' or `/dev/i2c/%d': %s\n", + i2cbus, i2cbus, strerror(ENOENT)); + } else { + fprintf(stderr, "Error: Could not open file " + "`%s': %s\n", filename, strerror(errno)); + if (errno == EACCES) + fprintf(stderr, "Run as root?\n"); + } + } + + return file; +} + +int set_slave_addr(int file, int address, int force) +{ + /* With force, let the user read from/write to the registers + even when a driver is also running */ + if (ioctl(file, force ? I2C_SLAVE_FORCE : I2C_SLAVE, address) < 0) { + fprintf(stderr, + "Error: Could not set address to 0x%02x: %s\n", + address, strerror(errno)); + return -errno; + } + + return 0; +} diff --git a/STM32MP157/source/A7/04_I2C/01_at24c02_test/i2cbusses.h b/STM32MP157/source/A7/04_I2C/01_at24c02_test/i2cbusses.h new file mode 100644 index 0000000..a192c7f --- /dev/null +++ b/STM32MP157/source/A7/04_I2C/01_at24c02_test/i2cbusses.h @@ -0,0 +1,44 @@ +/* + i2cbusses.h - Part of the i2c-tools package + + Copyright (C) 2004-2010 Jean Delvare + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301 USA. +*/ + +#ifndef _I2CBUSSES_H +#define _I2CBUSSES_H + +#include + +struct i2c_adap { + int nr; + char *name; + const char *funcs; + const char *algo; +}; + +struct i2c_adap *gather_i2c_busses(void); +void free_adapters(struct i2c_adap *adapters); + +int lookup_i2c_bus(const char *i2cbus_arg); +int parse_i2c_address(const char *address_arg, int all_addrs); +int open_i2c_dev(int i2cbus, char *filename, size_t size, int quiet); +int set_slave_addr(int file, int address, int force); + +#define MISSING_FUNC_FMT "Error: Adapter does not have %s capability\n" + +#endif diff --git a/STM32MP157/source/A7/04_I2C/01_at24c02_test/include/i2c/smbus.h b/STM32MP157/source/A7/04_I2C/01_at24c02_test/include/i2c/smbus.h new file mode 100644 index 0000000..3003ed7 --- /dev/null +++ b/STM32MP157/source/A7/04_I2C/01_at24c02_test/include/i2c/smbus.h @@ -0,0 +1,52 @@ +/* + smbus.h - SMBus level access helper functions + + Copyright (C) 1995-1997 Simon G. Vogl + Copyright (C) 1998-1999 Frodo Looijaard + Copyright (C) 2012-2017 Jean Delvare + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. +*/ + +#ifndef LIB_I2C_SMBUS_H +#define LIB_I2C_SMBUS_H + +#define I2C_API_VERSION 0x100 + +#include +#include + +extern __s32 i2c_smbus_access(int file, char read_write, __u8 command, + int size, union i2c_smbus_data *data); + +extern __s32 i2c_smbus_write_quick(int file, __u8 value); +extern __s32 i2c_smbus_read_byte(int file); +extern __s32 i2c_smbus_write_byte(int file, __u8 value); +extern __s32 i2c_smbus_read_byte_data(int file, __u8 command); +extern __s32 i2c_smbus_write_byte_data(int file, __u8 command, __u8 value); +extern __s32 i2c_smbus_read_word_data(int file, __u8 command); +extern __s32 i2c_smbus_write_word_data(int file, __u8 command, __u16 value); +extern __s32 i2c_smbus_process_call(int file, __u8 command, __u16 value); + +/* Returns the number of read bytes */ +extern __s32 i2c_smbus_read_block_data(int file, __u8 command, __u8 *values); +extern __s32 i2c_smbus_write_block_data(int file, __u8 command, __u8 length, + const __u8 *values); + +/* Returns the number of read bytes */ +/* Until kernel 2.6.22, the length is hardcoded to 32 bytes. If you + ask for less than 32 bytes, your code will only work with kernels + 2.6.23 and later. */ +extern __s32 i2c_smbus_read_i2c_block_data(int file, __u8 command, __u8 length, + __u8 *values); +extern __s32 i2c_smbus_write_i2c_block_data(int file, __u8 command, __u8 length, + const __u8 *values); + +/* Returns the number of read bytes */ +extern __s32 i2c_smbus_block_process_call(int file, __u8 command, __u8 length, + __u8 *values); + +#endif /* LIB_I2C_SMBUS_H */ diff --git a/STM32MP157/source/A7/04_I2C/01_at24c02_test/smbus.c b/STM32MP157/source/A7/04_I2C/01_at24c02_test/smbus.c new file mode 100644 index 0000000..df5a5ad --- /dev/null +++ b/STM32MP157/source/A7/04_I2C/01_at24c02_test/smbus.c @@ -0,0 +1,214 @@ +/* + smbus.c - SMBus level access helper functions + + Copyright (C) 1995-1997 Simon G. Vogl + Copyright (C) 1998-1999 Frodo Looijaard + Copyright (C) 2012-2013 Jean Delvare + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. +*/ + +#include +#include +#include +#include +#include +#include +#include + +/* Compatibility defines */ +#ifndef I2C_SMBUS_I2C_BLOCK_BROKEN +#define I2C_SMBUS_I2C_BLOCK_BROKEN I2C_SMBUS_I2C_BLOCK_DATA +#endif +#ifndef I2C_FUNC_SMBUS_PEC +#define I2C_FUNC_SMBUS_PEC I2C_FUNC_SMBUS_HWPEC_CALC +#endif + +__s32 i2c_smbus_access(int file, char read_write, __u8 command, + int size, union i2c_smbus_data *data) +{ + struct i2c_smbus_ioctl_data args; + __s32 err; + + args.read_write = read_write; + args.command = command; + args.size = size; + args.data = data; + + err = ioctl(file, I2C_SMBUS, &args); + if (err == -1) + err = -errno; + return err; +} + + +__s32 i2c_smbus_write_quick(int file, __u8 value) +{ + return i2c_smbus_access(file, value, 0, I2C_SMBUS_QUICK, NULL); +} + +__s32 i2c_smbus_read_byte(int file) +{ + union i2c_smbus_data data; + int err; + + err = i2c_smbus_access(file, I2C_SMBUS_READ, 0, I2C_SMBUS_BYTE, &data); + if (err < 0) + return err; + + return 0x0FF & data.byte; +} + +__s32 i2c_smbus_write_byte(int file, __u8 value) +{ + return i2c_smbus_access(file, I2C_SMBUS_WRITE, value, + I2C_SMBUS_BYTE, NULL); +} + +__s32 i2c_smbus_read_byte_data(int file, __u8 command) +{ + union i2c_smbus_data data; + int err; + + err = i2c_smbus_access(file, I2C_SMBUS_READ, command, + I2C_SMBUS_BYTE_DATA, &data); + if (err < 0) + return err; + + return 0x0FF & data.byte; +} + +__s32 i2c_smbus_write_byte_data(int file, __u8 command, __u8 value) +{ + union i2c_smbus_data data; + data.byte = value; + return i2c_smbus_access(file, I2C_SMBUS_WRITE, command, + I2C_SMBUS_BYTE_DATA, &data); +} + +__s32 i2c_smbus_read_word_data(int file, __u8 command) +{ + union i2c_smbus_data data; + int err; + + err = i2c_smbus_access(file, I2C_SMBUS_READ, command, + I2C_SMBUS_WORD_DATA, &data); + if (err < 0) + return err; + + return 0x0FFFF & data.word; +} + +__s32 i2c_smbus_write_word_data(int file, __u8 command, __u16 value) +{ + union i2c_smbus_data data; + data.word = value; + return i2c_smbus_access(file, I2C_SMBUS_WRITE, command, + I2C_SMBUS_WORD_DATA, &data); +} + +__s32 i2c_smbus_process_call(int file, __u8 command, __u16 value) +{ + union i2c_smbus_data data; + data.word = value; + if (i2c_smbus_access(file, I2C_SMBUS_WRITE, command, + I2C_SMBUS_PROC_CALL, &data)) + return -1; + else + return 0x0FFFF & data.word; +} + +/* Returns the number of read bytes */ +__s32 i2c_smbus_read_block_data(int file, __u8 command, __u8 *values) +{ + union i2c_smbus_data data; + int i, err; + + err = i2c_smbus_access(file, I2C_SMBUS_READ, command, + I2C_SMBUS_BLOCK_DATA, &data); + if (err < 0) + return err; + + for (i = 1; i <= data.block[0]; i++) + values[i-1] = data.block[i]; + return data.block[0]; +} + +__s32 i2c_smbus_write_block_data(int file, __u8 command, __u8 length, + const __u8 *values) +{ + union i2c_smbus_data data; + int i; + if (length > I2C_SMBUS_BLOCK_MAX) + length = I2C_SMBUS_BLOCK_MAX; + for (i = 1; i <= length; i++) + data.block[i] = values[i-1]; + data.block[0] = length; + return i2c_smbus_access(file, I2C_SMBUS_WRITE, command, + I2C_SMBUS_BLOCK_DATA, &data); +} + +/* Returns the number of read bytes */ +/* Until kernel 2.6.22, the length is hardcoded to 32 bytes. If you + ask for less than 32 bytes, your code will only work with kernels + 2.6.23 and later. */ +__s32 i2c_smbus_read_i2c_block_data(int file, __u8 command, __u8 length, + __u8 *values) +{ + union i2c_smbus_data data; + int i, err; + + if (length > I2C_SMBUS_BLOCK_MAX) + length = I2C_SMBUS_BLOCK_MAX; + data.block[0] = length; + + err = i2c_smbus_access(file, I2C_SMBUS_READ, command, + length == 32 ? I2C_SMBUS_I2C_BLOCK_BROKEN : + I2C_SMBUS_I2C_BLOCK_DATA, &data); + if (err < 0) + return err; + + for (i = 1; i <= data.block[0]; i++) + values[i-1] = data.block[i]; + return data.block[0]; +} + +__s32 i2c_smbus_write_i2c_block_data(int file, __u8 command, __u8 length, + const __u8 *values) +{ + union i2c_smbus_data data; + int i; + if (length > I2C_SMBUS_BLOCK_MAX) + length = I2C_SMBUS_BLOCK_MAX; + for (i = 1; i <= length; i++) + data.block[i] = values[i-1]; + data.block[0] = length; + return i2c_smbus_access(file, I2C_SMBUS_WRITE, command, + I2C_SMBUS_I2C_BLOCK_BROKEN, &data); +} + +/* Returns the number of read bytes */ +__s32 i2c_smbus_block_process_call(int file, __u8 command, __u8 length, + __u8 *values) +{ + union i2c_smbus_data data; + int i, err; + + if (length > I2C_SMBUS_BLOCK_MAX) + length = I2C_SMBUS_BLOCK_MAX; + for (i = 1; i <= length; i++) + data.block[i] = values[i-1]; + data.block[0] = length; + + err = i2c_smbus_access(file, I2C_SMBUS_WRITE, command, + I2C_SMBUS_BLOCK_PROC_CALL, &data); + if (err < 0) + return err; + + for (i = 1; i <= data.block[0]; i++) + values[i-1] = data.block[i]; + return data.block[0]; +} diff --git a/STM32MP157/开发板配套资料/datasheeet/01_Base_board(底板)/100ask_stm32mp157_pro底板_规格书/I2C/AT24cxx.pdf b/STM32MP157/开发板配套资料/datasheeet/01_Base_board(底板)/100ask_stm32mp157_pro底板_规格书/I2C/AT24cxx.pdf new file mode 100644 index 0000000..7099ab2 Binary files /dev/null and b/STM32MP157/开发板配套资料/datasheeet/01_Base_board(底板)/100ask_stm32mp157_pro底板_规格书/I2C/AT24cxx.pdf differ diff --git a/STM32MP157/开发板配套资料/原理图/04_Extend_modules(外设模块)/adxl345.zip b/STM32MP157/开发板配套资料/原理图/04_Extend_modules(外设模块)/adxl345.zip new file mode 100644 index 0000000..3d3347e Binary files /dev/null and b/STM32MP157/开发板配套资料/原理图/04_Extend_modules(外设模块)/adxl345.zip differ diff --git a/STM32MP157/开发板配套资料/原理图/04_Extend_modules(外设模块)/dac.zip b/STM32MP157/开发板配套资料/原理图/04_Extend_modules(外设模块)/dac.zip new file mode 100644 index 0000000..9282fc7 Binary files /dev/null and b/STM32MP157/开发板配套资料/原理图/04_Extend_modules(外设模块)/dac.zip differ diff --git a/STM32MP157/开发板配套资料/原理图/04_Extend_modules(外设模块)/dht11.zip b/STM32MP157/开发板配套资料/原理图/04_Extend_modules(外设模块)/dht11.zip new file mode 100644 index 0000000..d774e35 Binary files /dev/null and b/STM32MP157/开发板配套资料/原理图/04_Extend_modules(外设模块)/dht11.zip differ diff --git a/STM32MP157/开发板配套资料/原理图/04_Extend_modules(外设模块)/ds18b20.zip b/STM32MP157/开发板配套资料/原理图/04_Extend_modules(外设模块)/ds18b20.zip new file mode 100644 index 0000000..394dad8 Binary files /dev/null and b/STM32MP157/开发板配套资料/原理图/04_Extend_modules(外设模块)/ds18b20.zip differ diff --git a/STM32MP157/开发板配套资料/原理图/04_Extend_modules(外设模块)/eeprom.zip b/STM32MP157/开发板配套资料/原理图/04_Extend_modules(外设模块)/eeprom.zip new file mode 100644 index 0000000..e085c3e Binary files /dev/null and b/STM32MP157/开发板配套资料/原理图/04_Extend_modules(外设模块)/eeprom.zip differ diff --git a/STM32MP157/开发板配套资料/原理图/04_Extend_modules(外设模块)/gps.zip b/STM32MP157/开发板配套资料/原理图/04_Extend_modules(外设模块)/gps.zip new file mode 100644 index 0000000..0fd36d9 Binary files /dev/null and b/STM32MP157/开发板配套资料/原理图/04_Extend_modules(外设模块)/gps.zip differ diff --git a/STM32MP157/开发板配套资料/原理图/04_Extend_modules(外设模块)/imx6ull_extend_v10.pdf b/STM32MP157/开发板配套资料/原理图/04_Extend_modules(外设模块)/imx6ull_extend_v10.pdf new file mode 100644 index 0000000..245e4c1 Binary files /dev/null and b/STM32MP157/开发板配套资料/原理图/04_Extend_modules(外设模块)/imx6ull_extend_v10.pdf differ diff --git a/STM32MP157/开发板配套资料/原理图/04_Extend_modules(外设模块)/irda.zip b/STM32MP157/开发板配套资料/原理图/04_Extend_modules(外设模块)/irda.zip new file mode 100644 index 0000000..76d78f7 Binary files /dev/null and b/STM32MP157/开发板配套资料/原理图/04_Extend_modules(外设模块)/irda.zip differ diff --git a/STM32MP157/开发板配套资料/原理图/04_Extend_modules(外设模块)/oled.zip b/STM32MP157/开发板配套资料/原理图/04_Extend_modules(外设模块)/oled.zip new file mode 100644 index 0000000..a4e1296 Binary files /dev/null and b/STM32MP157/开发板配套资料/原理图/04_Extend_modules(外设模块)/oled.zip differ diff --git a/STM32MP157/开发板配套资料/原理图/04_Extend_modules(外设模块)/人体红外感应.zip b/STM32MP157/开发板配套资料/原理图/04_Extend_modules(外设模块)/人体红外感应.zip new file mode 100644 index 0000000..ed742f3 Binary files /dev/null and b/STM32MP157/开发板配套资料/原理图/04_Extend_modules(外设模块)/人体红外感应.zip differ diff --git a/STM32MP157/开发板配套资料/原理图/04_Extend_modules(外设模块)/步进电机驱动模块.zip b/STM32MP157/开发板配套资料/原理图/04_Extend_modules(外设模块)/步进电机驱动模块.zip new file mode 100644 index 0000000..0bec9dc Binary files /dev/null and b/STM32MP157/开发板配套资料/原理图/04_Extend_modules(外设模块)/步进电机驱动模块.zip differ diff --git a/STM32MP157/开发板配套资料/原理图/04_Extend_modules(外设模块)/超声波.zip b/STM32MP157/开发板配套资料/原理图/04_Extend_modules(外设模块)/超声波.zip new file mode 100644 index 0000000..312094f Binary files /dev/null and b/STM32MP157/开发板配套资料/原理图/04_Extend_modules(外设模块)/超声波.zip differ