Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

drivers/soft_i2c: Add bit-banging I2C using GPIO LL #20333

Open
wants to merge 5 commits into
base: master
Choose a base branch
from

Conversation

maribu
Copy link
Member

@maribu maribu commented Feb 2, 2024

Contribution description

This implements a bit-banged I2C bus using GPIO LL either using the periph_gpio_ll_open_drain feature or ,as fall-back, using the periph_gpio_ll_switch_dir feature.

The implementation should work with clock-stretching and arbitration. It should also be able to detect a locked bus and recover from it.

A pseudomodule soft_i2c_as_periph_i2c is added to allow the soft_i2c providing the periph_i2c API.

Testing procedure

I tested this using the following patch using an SHT3X breakout board connected to an nRF52840-DK:

--- a/tests/drivers/sht3x/Makefile
+++ b/tests/drivers/sht3x/Makefile
@@ -2,4 +2,19 @@ include ../Makefile.drivers_common

 USEMODULE += sht3x

+PIN_SCL ?= GPIO_PIN(0,27)
+PIN_SDA ?= GPIO_PIN(0,26)
+
+ifneq (,$(PIN_SCL))
+  CFLAGS += "-DSOFT_I2C_PARAM_SCL=$(PIN_SCL)"
+endif
+ifneq (,$(PIN_SDA))
+  CFLAGS += "-DSOFT_I2C_PARAM_SDA=$(PIN_SDA)"
+endif
+
+USEMODULE += soft_i2c
+USEMODULE += soft_i2c_as_periph_i2c
+
+CFLAGS += "-DSHT3X_PARAM_I2C_ADDR=SHT3X_I2C_ADDR_1"
+
 include $(RIOTBASE)/Makefile.include

Capture with a Logic Analyzer

20240202_13h50m15s_grim

Console output

 make BOARD=nrf52840dk flash term -j
Building application "tests_sht3x" for "nrf52840dk" with MCU "nrf52".

"make" -C /home/maribu/Repos/software/RIOT/soft_i2c/pkg/cmsis/ 
"make" -C /home/maribu/Repos/software/RIOT/soft_i2c/boards/common/init
"make" -C /home/maribu/Repos/software/RIOT/soft_i2c/boards/nrf52840dk
"make" -C /home/maribu/Repos/software/RIOT/soft_i2c/core
"make" -C /home/maribu/Repos/software/RIOT/soft_i2c/core/lib
"make" -C /home/maribu/Repos/software/RIOT/soft_i2c/cpu/nrf52
"make" -C /home/maribu/Repos/software/RIOT/soft_i2c/drivers
"make" -C /home/maribu/Repos/software/RIOT/soft_i2c/sys
"make" -C /home/maribu/Repos/software/RIOT/soft_i2c/boards/common/nrf52xxxdk
"make" -C /home/maribu/Repos/software/RIOT/soft_i2c/drivers/periph_common
"make" -C /home/maribu/Repos/software/RIOT/soft_i2c/drivers/sht3x
"make" -C /home/maribu/Repos/software/RIOT/soft_i2c/drivers/soft_i2c
"make" -C /home/maribu/Repos/software/RIOT/soft_i2c/cpu/cortexm_common
"make" -C /home/maribu/Repos/software/RIOT/soft_i2c/cpu/nrf52/periph
"make" -C /home/maribu/Repos/software/RIOT/soft_i2c/sys/auto_init
"make" -C /home/maribu/Repos/software/RIOT/soft_i2c/sys/checksum
"make" -C /home/maribu/Repos/software/RIOT/soft_i2c/cpu/nrf52/vectors
"make" -C /home/maribu/Repos/software/RIOT/soft_i2c/cpu/nrf5x_common
"make" -C /home/maribu/Repos/software/RIOT/soft_i2c/sys/div
"make" -C /home/maribu/Repos/software/RIOT/soft_i2c/sys/frac
"make" -C /home/maribu/Repos/software/RIOT/soft_i2c/sys/libc
"make" -C /home/maribu/Repos/software/RIOT/soft_i2c/sys/malloc_thread_safe
"make" -C /home/maribu/Repos/software/RIOT/soft_i2c/cpu/cortexm_common/periph
"make" -C /home/maribu/Repos/software/RIOT/soft_i2c/cpu/nrf5x_common/periph
"make" -C /home/maribu/Repos/software/RIOT/soft_i2c/sys/newlib_syscalls_default
"make" -C /home/maribu/Repos/software/RIOT/soft_i2c/sys/preprocessor
"make" -C /home/maribu/Repos/software/RIOT/soft_i2c/sys/stdio_uart
"make" -C /home/maribu/Repos/software/RIOT/soft_i2c/sys/tiny_strerror
"make" -C /home/maribu/Repos/software/RIOT/soft_i2c/sys/ztimer
   text	  data	   bss	   dec	   hex	filename
  13800	   140	  2848	 16788	  4194	/home/maribu/Repos/software/RIOT/soft_i2c/tests/drivers/sht3x/bin/nrf52840dk/tests_sht3x.elf
/home/maribu/Repos/software/RIOT/soft_i2c/dist/tools/openocd/openocd.sh flash /home/maribu/Repos/software/RIOT/soft_i2c/tests/drivers/sht3x/bin/nrf52840dk/tests_sht3x.elf
### Flashing Target ###
Open On-Chip Debugger 0.12.0+dev-snapshot (2024-01-17-08:38)
Licensed under GNU GPL v2
For bug reports, read
	http://openocd.org/doc/doxygen/bugs.html
DEPRECATED! use 'adapter serial' not 'jlink serial'
swd
Info : J-Link OB-SAM3U128-V2-NordicSemi compiled Nov  7 2022 16:21:57
Info : Hardware version: 1.00
Info : VTarget = 3.300 V
Info : clock speed 1000 kHz
Info : SWD DPIDR 0x2ba01477
Info : [nrf52.cpu] Cortex-M4 r0p1 processor detected
Info : [nrf52.cpu] target has 6 breakpoints, 4 watchpoints
Info : [nrf52.cpu] Examination succeed
Info : starting gdb server for nrf52.cpu on 0
Info : Listening on port 44223 for gdb connections
    TargetName         Type       Endian TapName            State       
--  ------------------ ---------- ------ ------------------ ------------
 0* nrf52.cpu          cortex_m   little nrf52.cpu          unknown
[nrf52.cpu] halted due to debug-request, current mode: Thread 
xPSR: 0x01000000 pc: 0x0000086c msp: 0x20000200
Info : nRF52840-xxAA(build code: AA) 1024kB Flash, 256kB RAM
Warn : Adding extra erase range, 0x00003674 .. 0x00003fff
auto erase enabled
wrote 13940 bytes from file /home/maribu/Repos/software/RIOT/soft_i2c/tests/drivers/sht3x/bin/nrf52840dk/tests_sht3x.elf in 0.634392s (21.459 KiB/s)
verified 13940 bytes in 0.067082s (202.935 KiB/s)
shutdown command invoked
Done flashing
/home/maribu/Repos/software/RIOT/soft_i2c/dist/tools/pyterm/pyterm -p "/dev/ttyACM1" -b "115200"  
2024-02-02 13:46:07,332 # Connect to serial port /dev/ttyACM1
Welcome to pyterm!
Type '/exit' to exit.
2024-02-02 13:46:08,335 # main(): This is RIOT! (Version: 2024.01-devel-802-g71cf5-drivers/soft_i2c)
2024-02-02 13:46:08,335 # SHT3X test application
2024-02-02 13:46:08,335 # 
2024-02-02 13:46:08,335 # +------------Initializing------------+
2024-02-02 13:46:08,335 # Initialization successful
2024-02-02 13:46:08,335 # 
2024-02-02 13:46:08,336 # 
2024-02-02 13:46:08,336 # +--------Starting Measurements--------+
2024-02-02 13:46:08,336 # Temperature [°C]: 21.84
2024-02-02 13:46:08,336 # Relative Humidity [%]: 42.67
2024-02-02 13:46:08,336 # +-------------------------------------+
2024-02-02 13:46:08,450 # Temperature [°C]: 21.91
2024-02-02 13:46:08,453 # Relative Humidity [%]: 42.76
2024-02-02 13:46:08,456 # +-------------------------------------+
2024-02-02 13:46:09,460 # Temperature [°C]: 21.88
2024-02-02 13:46:09,463 # Relative Humidity [%]: 42.72
2024-02-02 13:46:09,466 # +-------------------------------------+
2024-02-02 13:46:10,470 # Temperature [°C]: 21.88
2024-02-02 13:46:10,473 # Relative Humidity [%]: 42.75
2024-02-02 13:46:10,476 # +-------------------------------------+
2024-02-02 13:46:11,480 # Temperature [°C]: 21.89
2024-02-02 13:46:11,483 # Relative Humidity [%]: 42.68
2024-02-02 13:46:11,486 # +-------------------------------------+
2024-02-02 13:46:12,490 # Temperature [°C]: 21.88
2024-02-02 13:46:12,493 # Relative Humidity [%]: 42.72
2024-02-02 13:46:12,496 # +-------------------------------------+
2024-02-02 13:46:13,500 # Temperature [°C]: 21.89
2024-02-02 13:46:13,503 # Relative Humidity [%]: 42.72
2024-02-02 13:46:13,506 # +-------------------------------------+
2024-02-02 13:46:14,510 # Temperature [°C]: 21.94
2024-02-02 13:46:14,513 # Relative Humidity [%]: 42.77
2024-02-02 13:46:14,516 # +-------------------------------------+
2024-02-02 13:46:15,520 # Temperature [°C]: 23.3
2024-02-02 13:46:15,522 # Relative Humidity [%]: 44.45
2024-02-02 13:46:15,526 # +-------------------------------------+
2024-02-02 13:46:16,530 # Temperature [°C]: 24.68
2024-02-02 13:46:16,532 # Relative Humidity [%]: 48.83
2024-02-02 13:46:16,536 # +-------------------------------------+
2024-02-02 13:46:17,540 # Temperature [°C]: 25.66
2024-02-02 13:46:17,542 # Relative Humidity [%]: 52.15

Beware: This has not been tested on boards that have no open drain GPIOs but implement periph_gpio_ll_switch_dir. I'll add that in time.

Issues/PRs references

Depends on and includes:

@maribu maribu added State: WIP State: The PR is still work-in-progress and its code is not in its final presentable form yet Type: new feature The issue requests / The PR implemements a new feature for RIOT State: waiting for other PR State: The PR requires another PR to be merged first CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR labels Feb 2, 2024
@github-actions github-actions bot added Platform: ARM Platform: This PR/issue effects ARM-based platforms Area: doc Area: Documentation Area: tests Area: tests and testing framework Area: build system Area: Build system Platform: AVR Platform: This PR/issue effects AVR-based platforms Area: drivers Area: Device drivers Platform: ESP Platform: This PR/issue effects ESP-based platforms Area: cpu Area: CPU/MCU ports Area: sys Area: System labels Feb 2, 2024
@riot-ci
Copy link

riot-ci commented Feb 2, 2024

Murdock results

✔️ PASSED

b2e97dc fixup! drivers/periph_i2c: implement i2c_pin_sda() in C

Success Failures Total Runtime
10016 0 10016 10m:41s

Artifacts

This implements `i2c_pin_sda()` and `i2c_pin_scl()` as regular C
functions instead of preprocessor macros.
This implements a bit-banged I2C bus using GPIO LL either using the
`periph_gpio_ll_open_drain` feature or ,as fall-back, using the
`periph_gpio_ll_switch_dir` feature.

The implementation should work with clock-stretching and arbitration.
It should also be able to detect a locked bus and recover from it.
With the new feature it should be possible to just use a software
I2C bus instead of a `periph_i2c` using the same APIs.

I tested this using the following patch using an SHT3X breakout board
connected to an nRF52840-DK:

```diff
--- a/tests/drivers/sht3x/Makefile
+++ b/tests/drivers/sht3x/Makefile
@@ -2,4 +2,19 @@ include ../Makefile.drivers_common

 USEMODULE += sht3x

+PIN_SCL ?= GPIO_PIN(0,27)
+PIN_SDA ?= GPIO_PIN(0,26)
+
+ifneq (,$(PIN_SCL))
+  CFLAGS += "-DSOFT_I2C_PARAM_SCL=$(PIN_SCL)"
+endif
+ifneq (,$(PIN_SDA))
+  CFLAGS += "-DSOFT_I2C_PARAM_SDA=$(PIN_SDA)"
+endif
+
+USEMODULE += soft_i2c
+USEMODULE += soft_i2c_as_periph_i2c
+
+CFLAGS += "-DSHT3X_PARAM_I2C_ADDR=SHT3X_I2C_ADDR_1"
+
 include $(RIOTBASE)/Makefile.include
```
Just passing the flag `SOFT_I2C=` while building will use the software
I2C bus instead of the hardware I2C bus.
@github-actions github-actions bot removed Platform: AVR Platform: This PR/issue effects AVR-based platforms Platform: ESP Platform: This PR/issue effects ESP-based platforms labels Feb 5, 2024
@benpicco benpicco removed the State: waiting for other PR State: The PR requires another PR to be merged first label Feb 5, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area: build system Area: Build system Area: cpu Area: CPU/MCU ports Area: doc Area: Documentation Area: drivers Area: Device drivers Area: sys Area: System Area: tests Area: tests and testing framework CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR Platform: ARM Platform: This PR/issue effects ARM-based platforms State: WIP State: The PR is still work-in-progress and its code is not in its final presentable form yet Type: new feature The issue requests / The PR implemements a new feature for RIOT
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants