-
Notifications
You must be signed in to change notification settings - Fork 2k
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
base: master
Are you sure you want to change the base?
Conversation
1baf069
to
f9c952d
Compare
@@ -281,55 +248,47 @@ static void _spi_acquire(spi_t bus, spi_mode_t mode, spi_clk_t clk) | |||
* to mitigate the rounding error due to integer arithmetic, the | |||
* equation is modified to | |||
* BAUD.reg = ((f_ref + f_bus) / (2 * f_bus) - 1) */ | |||
const uint8_t baud = (gclk_src + clk) / (2 * clk) - 1; | |||
uint8_t baud = (gclk_src + clk) / (2 * clk) - 1; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why do you unconst this (line seems uncanged otherwise)
same for ctrla
liter (const correctness) might not like that change
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For consistency with the other variables holding the values to store into the registers.
56ef1ea
to
08a71df
Compare
08a71df
to
b2bb805
Compare
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.
For `gpio_ll_print_conf()` we need to include `<stdio.h>`, when not using `fmt.h`.
Now that time-sharing SERCOMs is possible, we can provide the SPI on D11/D12/D13 (backed by SERCOM3) also when the UART on D0/D1 (also backed by SERCOM3) is used.
b2bb805
to
f5abef9
Compare
#if defined(CPU_COMMON_SAMD21) | ||
PM->APBCMASK.reg |= (PM_APBCMASK_SERCOM0 << sercom); | ||
#elif defined (CPU_COMMON_SAMD5X) | ||
if (sercom < 2) { | ||
MCLK->APBAMASK.reg |= (1 << (sercom + 12)); | ||
} else if (sercom < 4) { | ||
MCLK->APBBMASK.reg |= (1 << (sercom + 7)); | ||
} else { | ||
MCLK->APBDMASK.reg |= (1 << (sercom - 4)); | ||
} | ||
#else | ||
if (sercom < 5) { | ||
MCLK->APBCMASK.reg |= (MCLK_APBCMASK_SERCOM0 << sercom); | ||
} | ||
#if defined(CPU_COMMON_SAML21) | ||
else { | ||
MCLK->APBDMASK.reg |= (MCLK_APBDMASK_SERCOM5); | ||
} | ||
#endif /* CPU_COMMON_SAML21 */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since you basically have an #ifdef
case for each CPU family, I think it would be more readable to move _sercom_apb_enable()
to periph_cpu.h
of the respective CPU family memember.
So you'd only be left with
static inline void _sercom_apb_enable(sercom_t sercom)
{
PM->APBCMASK.reg |= PM_APBCMASK_SERCOM0 << sercom;
}
on samd21 and
static inline void _sercom_apb_enable(sercom_t sercom)
{
MCLK->APBCMASK.reg |= MCLK_APBCMASK_SERCOM0 << sercom;
}
on saml1x, etc
Contribution description
This adds a
periph_sercom
feature and implementation whichperiph_i2c
,periph_uart
, andperiph_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()
andi2c_release()
/spi_release()
, UARTs are typically not shared and most users will not calluart_poweron()
anduart_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
Issues/PRs references
None