From 6b0082bb3fa86583062225c2faf9b78fde9c317b Mon Sep 17 00:00:00 2001 From: Marian Buschsieweke Date: Fri, 22 Mar 2019 17:50:08 +0100 Subject: [PATCH] shell: Add command i2c_scan Add a trivial shell program that scans for all slaves on an I2C bus by iterating all of the possible 127 I2C addresses and checking for the ACK of the device. --- makefiles/pseudomodules.inc.mk | 1 + sys/Makefile.dep | 4 + sys/shell/commands/Makefile | 4 + sys/shell/commands/sc_i2c_scan.c | 112 ++++++++++++++++++++++++++++ sys/shell/commands/shell_commands.c | 7 ++ 5 files changed, 128 insertions(+) create mode 100644 sys/shell/commands/sc_i2c_scan.c diff --git a/makefiles/pseudomodules.inc.mk b/makefiles/pseudomodules.inc.mk index d4057d8e78..165d9e1be0 100644 --- a/makefiles/pseudomodules.inc.mk +++ b/makefiles/pseudomodules.inc.mk @@ -35,6 +35,7 @@ PSEUDOMODULES += gnrc_sixlowpan_router PSEUDOMODULES += gnrc_sixlowpan_router_default PSEUDOMODULES += gnrc_sock_check_reuse PSEUDOMODULES += gnrc_txtsnd +PSEUDOMODULES += i2c_scan PSEUDOMODULES += l2filter_blacklist PSEUDOMODULES += l2filter_whitelist PSEUDOMODULES += lis2dh12_spi diff --git a/sys/Makefile.dep b/sys/Makefile.dep index ce7f6f2c82..f9afc587e3 100644 --- a/sys/Makefile.dep +++ b/sys/Makefile.dep @@ -2,6 +2,10 @@ ifneq (,$(filter eepreg,$(USEMODULE))) FEATURES_REQUIRED += periph_eeprom endif +ifneq (,$(filter i2c_scan,$(USEMODULE))) + FEATURES_REQUIRED += periph_i2c +endif + ifneq (,$(filter prng_fortuna,$(USEMODULE))) CFLAGS += -DCRYPTO_AES endif diff --git a/sys/shell/commands/Makefile b/sys/shell/commands/Makefile index 6c41e53ca9..d7d860a0a1 100644 --- a/sys/shell/commands/Makefile +++ b/sys/shell/commands/Makefile @@ -77,4 +77,8 @@ ifneq (,$(filter periph_rtc,$(USEMODULE))) SRC += sc_rtc.c endif +ifneq (,$(filter i2c_scan,$(USEMODULE))) + SRC += sc_i2c_scan.c +endif + include $(RIOTBASE)/Makefile.base diff --git a/sys/shell/commands/sc_i2c_scan.c b/sys/shell/commands/sc_i2c_scan.c new file mode 100644 index 0000000000..2ef6b63dea --- /dev/null +++ b/sys/shell/commands/sc_i2c_scan.c @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2019 Otto-von-Guericke-Universität Magdeburg + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup sys_shell_commands + * @{ + * + * @file + * @brief An I2C bus scanner + * + * @author Marian Buschsieweke + * + * @} + */ + +#include +#include +#include +#include +#include + +#include "board.h" +#include "periph/i2c.h" + +static int get_dev(i2c_t *dev, int argc, char **argv) +{ + if (argc == 2) { + int idx = atoi(argv[1]); + if ((idx < 0) || (idx >= (int)I2C_NUMOF)) { + printf("I2C device with number \"%s\" not found\n", argv[1]); + } + else { + *dev = I2C_DEV(idx); + return 0; + } + } + printf("Usage: %s [DEVICE_NUMBER]\n", argv[0]); + return -1; +} + +static inline int is_addr_reserved(uint16_t addr) +{ + if ((addr < 0x0e) || (addr > 0x77)) + return 1; + + return 0; +} + +int _i2c_scan(int argc, char **argv) +{ + i2c_t dev; + if (get_dev(&dev, argc, argv)) { + return -1; + } + + printf("Scanning I2C device %s...\n", argv[1]); + if (i2c_acquire(dev)){ + puts("Failed to acquire I2C device"); + return -1; + } + + puts( + "addr not ack'ed = \"-\", addr ack'ed = \"X\", addr reserved = \"R\", error = \"E\"\n" + " 0 1 2 3 4 5 6 7 8 9 a b c d e f" + ); + + for (char i = 0; i < 8; i++) { + char row[] = { '0', 'x', '0' + i, '0', '\0' }; + fputs(row, stdout); + uint16_t addr = i; + addr <<= 4; + for (unsigned j = 0; j < 16; j++) { + char str[] = { ' ', '-', '\0' }; + if (is_addr_reserved(addr)) { + str[1] = 'R'; + } + else { + char dummy[1]; + int retval; + while (-EAGAIN == (retval = i2c_read_byte(dev, addr, dummy, 0))) { + /* retry until bus arbitration succeeds */ + } + + switch (retval) { + case 0: + /* success: Device did respond */ + str[1] = 'X'; + break; + case -ENXIO: + /* No ACK --> no device */ + break; + default: + /* Some unexpected error */ + str[1] = 'E'; + break; + } + } + + fputs(str, stdout); + addr++; + } + puts(""); + } + + i2c_release(dev); + return 0; +} diff --git a/sys/shell/commands/shell_commands.c b/sys/shell/commands/shell_commands.c index b0b689810a..176e76cd98 100644 --- a/sys/shell/commands/shell_commands.c +++ b/sys/shell/commands/shell_commands.c @@ -145,6 +145,10 @@ extern int _cord_ep_handler(int argc, char **argv); extern int _app_metadata_handler(int argc, char **argv); #endif +#ifdef MODULE_I2C_SCAN +extern int _i2c_scan(int argc, char **argv); +#endif + const shell_command_t _shell_command_list[] = { {"reboot", "Reboot the node", _reboot_handler}, #ifdef MODULE_CONFIG @@ -237,6 +241,9 @@ const shell_command_t _shell_command_list[] = { #endif #ifdef MODULE_APP_METADATA {"app_metadata", "Returns application metadata", _app_metadata_handler }, +#endif +#ifdef MODULE_I2C_SCAN + { "i2c_scan", "Performs an I2C bus scan", _i2c_scan }, #endif {NULL, NULL, NULL} };