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

cpu/sam0_common: Implement time-sharing of SERCOMs #21029

Draft
wants to merge 10 commits into
base: master
Choose a base branch
from

Conversation

maribu
Copy link
Member

@maribu maribu commented Nov 21, 2024

Contribution description

This adds a periph_sercom feature and implementation which periph_i2c, periph_uart, and periph_spi are implemented on top. This allows for sharing a single SERCOM instance to provide multiple serial interfaces (in round-robin time-sharing fashion).

Note

In practice, a SERCOM can often not be shared if it needs to provide an UART.

Background:

While code using the I2C/SPI APIs is already optimized to share the peripheral with i2c_acquire()/spi_acquire() and i2c_release()/spi_release(), UARTs are typically not shared and most users will not call uart_poweron() and uart_poweroff() to only have the SERCOM in UART mode when actually needed. Worse: For many use cases (such as stdin), the UART will need to be constantly running, as receiving data happens asynchronously at unpredictable points in time.

Testing procedure

make BOARD=adafruit-metro-m4-express flash term -C tests/periph/selftest_shield

2024-11-21 20:29:42,410 # ALL TESTS SUCCEEDED
2024-11-21 20:29:42,395 # main(): This is RIOT! (Version: 2025.01-devel-156-g1baf0-cpu/sam0_common/periph_sercom)
2024-11-21 20:29:42,396 # self-testing peripheral drivers
2024-11-21 20:29:42,396 # ===============================
2024-11-21 20:29:42,396 # Starting test for GPIO at tests/periph/selftest_shield/main.c:350
2024-11-21 20:29:42,396 # [OK]
2024-11-21 20:29:42,397 # Starting test for GPIO at tests/periph/selftest_shield/main.c:372
2024-11-21 20:29:42,397 # [OK]
2024-11-21 20:29:42,397 # Starting test for GPIO at tests/periph/selftest_shield/main.c:402
2024-11-21 20:29:42,397 # [OK]
2024-11-21 20:29:42,397 # Starting test for GPIO at tests/periph/selftest_shield/main.c:432
2024-11-21 20:29:42,397 # (skipped)
2024-11-21 20:29:42,398 # Starting test for GPIO at tests/periph/selftest_shield/main.c:458
2024-11-21 20:29:42,398 # (skipped)
2024-11-21 20:29:42,398 # Starting test for GPIO-IRQ at tests/periph/selftest_shield/main.c:505
2024-11-21 20:29:42,398 # [OK]
2024-11-21 20:29:42,399 # Starting test for GPIO-IRQ at tests/periph/selftest_shield/main.c:571
2024-11-21 20:29:42,399 # [OK]
2024-11-21 20:29:42,399 # Starting test for GPIO-IRQ at tests/periph/selftest_shield/main.c:637
2024-11-21 20:29:42,399 # [OK]
2024-11-21 20:29:42,399 # Starting test for I2C at tests/periph/selftest_shield/main.c:711
2024-11-21 20:29:42,399 # [OK]
2024-11-21 20:29:42,400 # Starting test for UART at tests/periph/selftest_shield/main.c:806
2024-11-21 20:29:42,400 # [OK]
2024-11-21 20:29:42,400 # Starting test for UART at tests/periph/selftest_shield/main.c:815
2024-11-21 20:29:42,400 # [OK]
2024-11-21 20:29:42,400 # Starting test for SPI at tests/periph/selftest_shield/main.c:858
2024-11-21 20:29:42,401 # [OK]
2024-11-21 20:29:42,401 # Starting test for SPI at tests/periph/selftest_shield/main.c:858
2024-11-21 20:29:42,401 # [OK]
2024-11-21 20:29:42,401 # Starting test for SPI at tests/periph/selftest_shield/main.c:858
2024-11-21 20:29:42,401 # [OK]
2024-11-21 20:29:42,402 # Starting test for SPI at tests/periph/selftest_shield/main.c:858
2024-11-21 20:29:42,402 # [OK]
2024-11-21 20:29:42,402 # Starting test for SPI at tests/periph/selftest_shield/main.c:858
2024-11-21 20:29:42,402 # [OK]
2024-11-21 20:29:42,402 # Starting test for SPI at tests/periph/selftest_shield/main.c:858
2024-11-21 20:29:42,402 # [OK]
2024-11-21 20:29:42,403 # Starting test for SPI at tests/periph/selftest_shield/main.c:858
2024-11-21 20:29:42,403 # [OK]
2024-11-21 20:29:42,403 # Starting test for SPI at tests/periph/selftest_shield/main.c:858
2024-11-21 20:29:42,403 # [OK]
2024-11-21 20:29:42,404 # Starting test for SPI at tests/periph/selftest_shield/main.c:858
2024-11-21 20:29:42,404 # [OK]
2024-11-21 20:29:42,404 # Starting test for SPI at tests/periph/selftest_shield/main.c:858
2024-11-21 20:29:42,404 # [OK]
2024-11-21 20:29:42,404 # Starting test for SPI at tests/periph/selftest_shield/main.c:858
2024-11-21 20:29:42,405 # [OK]
2024-11-21 20:29:42,405 # Starting test for SPI at tests/periph/selftest_shield/main.c:858
2024-11-21 20:29:42,405 # [OK]
2024-11-21 20:29:42,405 # Starting test for SPI at tests/periph/selftest_shield/main.c:858
2024-11-21 20:29:42,405 # [OK]
2024-11-21 20:29:42,406 # Starting test for SPI at tests/periph/selftest_shield/main.c:858
2024-11-21 20:29:42,406 # [OK]
2024-11-21 20:29:42,406 # Starting test for SPI at tests/periph/selftest_shield/main.c:858
2024-11-21 20:29:42,406 # [OK]
2024-11-21 20:29:42,406 # Starting test for SPI at tests/periph/selftest_shield/main.c:858
2024-11-21 20:29:42,406 # [OK]
2024-11-21 20:29:42,407 # Starting test for SPI at tests/periph/selftest_shield/main.c:858
2024-11-21 20:29:42,407 # [OK]
2024-11-21 20:29:42,407 # Starting test for SPI at tests/periph/selftest_shield/main.c:858
2024-11-21 20:29:42,407 # [OK]
2024-11-21 20:29:42,408 # Starting test for SPI at tests/periph/selftest_shield/main.c:858
2024-11-21 20:29:42,408 # [OK]
2024-11-21 20:29:42,408 # Starting test for SPI at tests/periph/selftest_shield/main.c:858
2024-11-21 20:29:42,408 # [OK]
2024-11-21 20:29:42,408 # Starting test for SPI at tests/periph/selftest_shield/main.c:858
2024-11-21 20:29:42,408 # [OK]
2024-11-21 20:29:42,409 # Starting test for SPI at tests/periph/selftest_shield/main.c:858
2024-11-21 20:29:42,409 # [OK]
2024-11-21 20:29:42,409 # Starting test for SPI at tests/periph/selftest_shield/main.c:858
2024-11-21 20:29:42,409 # [OK]
2024-11-21 20:29:42,409 # Starting test for SPI at tests/periph/selftest_shield/main.c:858
2024-11-21 20:29:42,409 # [OK]
2024-11-21 20:29:42,410 # Starting test for ADC at tests/periph/selftest_shield/main.c:1072
2024-11-21 20:29:42,410 # [OK]
2024-11-21 20:29:42,410 # 
2024-11-21 20:29:42,410 # 
2024-11-21 20:29:42,410 # ALL TESTS SUCCEEDED
2024-11-21 20:29:42,410 # { "threads": [{ "name": "main", "stack_size": 1536, "stack_used": 572}]}

Issues/PRs references

None

@github-actions github-actions bot added Platform: ARM Platform: This PR/issue effects ARM-based platforms Area: tests Area: tests and testing framework Area: build system Area: Build system Area: boards Area: Board ports labels Nov 21, 2024
@maribu maribu added the CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR label Nov 21, 2024
@github-actions github-actions bot added the Area: cpu Area: CPU/MCU ports label Nov 21, 2024
@maribu maribu changed the title Cpu/sam0 common/periph sercom cpu/sam0_common: Implement time-sharing of SERCOMs Nov 21, 2024
@@ -104,7 +104,7 @@ static const adc_conf_chan_t adc_channels[] = {
*/
static const i2c_conf_t i2c_config[] = {
{
.dev = &(SERCOM3->I2CM),
.sercom = 3,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We already have sercom_id(), that would be less invasive

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a bit more efficient, though. And the conversion is pretty straight-forward.

But I can change this to use sercom_id(), if you prefer compatibility with out-of-tree boards.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Whats the verdict? Use uint8_t sercom and touch all boards for better efficiency, or stick with void *dev for backward compatibility with out-of-tree boards?

@riot-ci
Copy link

riot-ci commented Nov 21, 2024

Murdock results

FAILED

56ef1ea cpu/sam0_common/periph_gpio_ll: Add missing include

Success Failures Total Runtime
2092 0 9487 03m:56s

Artifacts

This adds a `periph_sercom` feature and implementation which
`periph_i2c`, `periph_uart`, and `periph_spi` are implemented on top.
This allows for sharing a single SERCOM instance to provide multiple
serial interfaces (in round-robin time-sharing fashion).

Note: In practice, a SERCOM can often not be shared if it needs to
      provide an UART.

Background:

While code using the I2C/SPI APIs is already optimized to share the
peripheral with `i2c_acquire()`/`spi_acquire()` and
`i2c_release()`/`spi_release()`, UARTs are typically not shared and most
users will not call `uart_poweron()` and `uart_poweroff()` to only have
the SERCOM in UART mode when actually needed. Worse: For many use cases
(such as stdin), the UART will need to be constantly running, as
receiving data happens asynchronously at unpredictable points in time.
Now that sharing SERCOMs is implemented, we can make use of that :)

A warning is emitted if this is actually done, as sharing with UART is
often not working as expected.
Calling `uart_poweroff()` when done with the UART test allows sharing
the underlying hardware e.g. to provide other peripheral interfaces.
One example of this would be the SERCOM3 on the Adafruit Metro M4
Express that is used to provide UART on D1/D0 and SPI on D11/D12/D13.
We cannot use the D0/D1 UART if it is also used for STDIO. However,
the logic did not take into account whether `stdio_uart` was used at
all. This fixes the issue.
The M4 Express does now have an I2C and an UART compatible with Arduino
Shields, so we can expose them.
@maribu maribu force-pushed the cpu/sam0_common/periph_sercom branch from 1baf069 to f9c952d Compare November 21, 2024 21:42
cpu/sam0_common/periph/sercom.c Show resolved Hide resolved
cpu/sam0_common/periph/sercom.c Outdated Show resolved Hide resolved
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area: boards Area: Board ports Area: build system Area: Build system Area: cpu Area: CPU/MCU ports 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
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants