diff --git a/boards/adafruit-grand-central-m4-express/include/periph_conf.h b/boards/adafruit-grand-central-m4-express/include/periph_conf.h index 49d5546179da..6c879841b32c 100644 --- a/boards/adafruit-grand-central-m4-express/include/periph_conf.h +++ b/boards/adafruit-grand-central-m4-express/include/periph_conf.h @@ -324,14 +324,6 @@ static const uart_conf_t uart_config[] = { }, }; -/* interrupt function name mapping */ -#define UART_0_ISR isr_sercom0_2 -#define UART_0_ISR_TX isr_sercom0_0 -#define UART_1_ISR isr_sercom4_2 -#define UART_1_ISR_TX isr_sercom4_0 -#define UART_2_ISR isr_sercom1_2 -#define UART_2_ISR_TX isr_sercom1_0 - #define UART_NUMOF ARRAY_SIZE(uart_config) /** @} */ diff --git a/boards/adafruit-itsybitsy-m4/include/periph_conf.h b/boards/adafruit-itsybitsy-m4/include/periph_conf.h index 48b762427e00..f26c5cfc67b3 100644 --- a/boards/adafruit-itsybitsy-m4/include/periph_conf.h +++ b/boards/adafruit-itsybitsy-m4/include/periph_conf.h @@ -105,10 +105,6 @@ static const uart_conf_t uart_config[] = { }, }; -/* interrupt function name mapping */ -#define UART_0_ISR isr_sercom3_2 -#define UART_0_ISR_TX isr_sercom3_0 - #define UART_NUMOF ARRAY_SIZE(uart_config) /** @} */ diff --git a/boards/adafruit-metro-m4-express/include/arduino_iomap.h b/boards/adafruit-metro-m4-express/include/arduino_iomap.h index c12257e23fc5..22cfec3beb56 100644 --- a/boards/adafruit-metro-m4-express/include/arduino_iomap.h +++ b/boards/adafruit-metro-m4-express/include/arduino_iomap.h @@ -100,14 +100,8 @@ extern "C" { /** * @brief SPI_DEV(1) is connected to D11/D12/D13 - * - * The SPI on D11/D12/D13 is only available when `periph_uart` is not used due - * to a conflicting use of the same SERCOM. If it is available, it is the last - * SPI bus. */ -#if !MODULE_PERIPH_UART -# define ARDUINO_SPI_D11D12D13 SPI_DEV(1) -#endif +#define ARDUINO_SPI_D11D12D13 SPI_DEV(1) /** @} */ /** diff --git a/boards/adafruit-metro-m4-express/include/periph_conf.h b/boards/adafruit-metro-m4-express/include/periph_conf.h index 820c340b3205..a3ab614040e2 100644 --- a/boards/adafruit-metro-m4-express/include/periph_conf.h +++ b/boards/adafruit-metro-m4-express/include/periph_conf.h @@ -169,7 +169,6 @@ static const spi_conf_t spi_config[] = { .rx_trigger = SERCOM2_DMAC_ID_RX, #endif }, -#if !MODULE_PERIPH_UART { /* D11=MOSI, D12=MISO, D13=SCK */ .dev = &(SERCOM3->SPI), .miso_pin = GPIO_PIN(PA, 17), /* C: SERCOM1.1, D: SERCOM3.0 */ @@ -181,12 +180,11 @@ static const spi_conf_t spi_config[] = { .miso_pad = SPI_PAD_MISO_0, .mosi_pad = SPI_PAD_MOSI_3_SCK_1, .gclk_src = SAM0_GCLK_PERIPH, -# if MODULE_PERIPH_DMA +#if MODULE_PERIPH_DMA .tx_trigger = SERCOM3_DMAC_ID_TX, .rx_trigger = SERCOM3_DMAC_ID_RX, -# endif - }, #endif + }, #if MODULE_PERIPH_SPI_ON_QSPI { /* QSPI in SPI mode */ .dev = QSPI, @@ -253,10 +251,6 @@ static const uart_conf_t uart_config[] = { }, }; -/* interrupt function name mapping */ -#define UART_0_ISR isr_sercom3_2 -#define UART_0_ISR_TX isr_sercom3_0 - #define UART_NUMOF ARRAY_SIZE(uart_config) /** @} */ diff --git a/boards/adafruit-pybadge/include/periph_conf.h b/boards/adafruit-pybadge/include/periph_conf.h index 2b5eeef89461..64eba10e6dbc 100644 --- a/boards/adafruit-pybadge/include/periph_conf.h +++ b/boards/adafruit-pybadge/include/periph_conf.h @@ -105,10 +105,6 @@ static const uart_conf_t uart_config[] = { } }; -/* interrupt function name mapping */ -#define UART_0_ISR isr_sercom5_2 -#define UART_0_ISR_TX isr_sercom5_0 - #define UART_NUMOF ARRAY_SIZE(uart_config) /** @} */ diff --git a/boards/arduino-mkrwan1300/include/periph_conf.h b/boards/arduino-mkrwan1300/include/periph_conf.h index fc905952e15a..a792611528cc 100644 --- a/boards/arduino-mkrwan1300/include/periph_conf.h +++ b/boards/arduino-mkrwan1300/include/periph_conf.h @@ -38,8 +38,8 @@ extern "C" { static const uart_conf_t uart_config[] = { { .dev = &SERCOM5->USART, - .rx_pin = GPIO_PIN(PB,23), /* ARDUINO_PIN_13, RX Pin */ - .tx_pin = GPIO_PIN(PB,22), /* ARDUINO_PIN_14, TX Pin */ + .rx_pin = GPIO_PIN(PB, 23), /* ARDUINO_PIN_13, RX Pin */ + .tx_pin = GPIO_PIN(PB, 22), /* ARDUINO_PIN_14, TX Pin */ #ifdef MODULE_PERIPH_UART_HW_FC .rts_pin = GPIO_UNDEF, .cts_pin = GPIO_UNDEF, @@ -52,8 +52,8 @@ static const uart_conf_t uart_config[] = { }, { /* LoRa module */ .dev = &SERCOM4->USART, - .rx_pin = GPIO_PIN(PA,15), - .tx_pin = GPIO_PIN(PA,12), + .rx_pin = GPIO_PIN(PA, 15), + .tx_pin = GPIO_PIN(PA, 12), #ifdef MODULE_PERIPH_UART_HW_FC .rts_pin = GPIO_UNDEF, .cts_pin = GPIO_UNDEF, @@ -66,10 +66,6 @@ static const uart_conf_t uart_config[] = { }, }; -/* interrupt function name mapping */ -#define UART_0_ISR isr_sercom5 -#define UART_1_ISR isr_sercom4 - #define UART_NUMOF ARRAY_SIZE(uart_config) /** @} */ diff --git a/boards/arduino-nano-33-iot/include/periph_conf.h b/boards/arduino-nano-33-iot/include/periph_conf.h index 932ff5151060..2d4c4d08c25b 100644 --- a/boards/arduino-nano-33-iot/include/periph_conf.h +++ b/boards/arduino-nano-33-iot/include/periph_conf.h @@ -119,8 +119,8 @@ static const tc32_conf_t timer_config[] = { static const uart_conf_t uart_config[] = { { .dev = &SERCOM5->USART, - .rx_pin = GPIO_PIN(PB,23), - .tx_pin = GPIO_PIN(PB,22), + .rx_pin = GPIO_PIN(PB, 23), + .tx_pin = GPIO_PIN(PB, 22), #ifdef MODULE_SAM0_PERIPH_UART_HW_FC .rts_pin = GPIO_UNDEF, .cts_pin = GPIO_UNDEF, @@ -133,9 +133,6 @@ static const uart_conf_t uart_config[] = { } }; -/* interrupt function name mapping */ -#define UART_0_ISR isr_sercom5 - #define UART_NUMOF ARRAY_SIZE(uart_config) /** @} */ diff --git a/boards/common/arduino-mkr/include/periph_conf.h b/boards/common/arduino-mkr/include/periph_conf.h index 25f52b025c00..03e081d02817 100644 --- a/boards/common/arduino-mkr/include/periph_conf.h +++ b/boards/common/arduino-mkr/include/periph_conf.h @@ -38,8 +38,8 @@ extern "C" { static const uart_conf_t uart_config[] = { { .dev = &SERCOM5->USART, - .rx_pin = GPIO_PIN(PB,23), /* ARDUINO_PIN_13, RX Pin */ - .tx_pin = GPIO_PIN(PB,22), /* ARDUINO_PIN_14, TX Pin */ + .rx_pin = GPIO_PIN(PB, 23), /* ARDUINO_PIN_13, RX Pin */ + .tx_pin = GPIO_PIN(PB, 22), /* ARDUINO_PIN_14, TX Pin */ #ifdef MODULE_PERIPH_UART_HW_FC .rts_pin = GPIO_UNDEF, .cts_pin = GPIO_UNDEF, @@ -52,9 +52,6 @@ static const uart_conf_t uart_config[] = { } }; -/* interrupt function name mapping */ -#define UART_0_ISR isr_sercom5 - #define UART_NUMOF ARRAY_SIZE(uart_config) /** @} */ diff --git a/boards/common/arduino-zero/include/periph_conf.h b/boards/common/arduino-zero/include/periph_conf.h index 040e22d31680..b979feb991e6 100644 --- a/boards/common/arduino-zero/include/periph_conf.h +++ b/boards/common/arduino-zero/include/periph_conf.h @@ -127,8 +127,8 @@ static const tc32_conf_t timer_config[] = { static const uart_conf_t uart_config[] = { { .dev = &SERCOM5->USART, - .rx_pin = GPIO_PIN(PB,23), - .tx_pin = GPIO_PIN(PB,22), + .rx_pin = GPIO_PIN(PB, 23), + .tx_pin = GPIO_PIN(PB, 22), #ifdef MODULE_PERIPH_UART_HW_FC .rts_pin = GPIO_UNDEF, .cts_pin = GPIO_UNDEF, @@ -141,8 +141,8 @@ static const uart_conf_t uart_config[] = { }, { .dev = &SERCOM0->USART, - .rx_pin = GPIO_PIN(PA,11), - .tx_pin = GPIO_PIN(PA,10), + .rx_pin = GPIO_PIN(PA, 11), + .tx_pin = GPIO_PIN(PA, 10), #ifdef MODULE_PERIPH_UART_HW_FC .rts_pin = GPIO_UNDEF, .cts_pin = GPIO_UNDEF, @@ -155,10 +155,6 @@ static const uart_conf_t uart_config[] = { } }; -/* interrupt function name mapping */ -#define UART_0_ISR isr_sercom5 -#define UART_1_ISR isr_sercom0 - #define UART_NUMOF ARRAY_SIZE(uart_config) /** @} */ diff --git a/boards/common/saml1x/include/periph_conf.h b/boards/common/saml1x/include/periph_conf.h index d416c0f63363..7d508a9dfcc8 100644 --- a/boards/common/saml1x/include/periph_conf.h +++ b/boards/common/saml1x/include/periph_conf.h @@ -111,12 +111,6 @@ static const uart_conf_t uart_config[] = { } }; -/* interrupt function name mapping */ -#define UART_0_ISR isr_sercom2_2 -#define UART_0_ISR_TX isr_sercom2_0 -#define UART_1_ISR isr_sercom1_2 -#define UART_1_ISR_TX isr_sercom1_0 - #define UART_NUMOF ARRAY_SIZE(uart_config) /** @} */ diff --git a/boards/feather-m0/include/periph_conf.h b/boards/feather-m0/include/periph_conf.h index 0808bb3393a0..bcb4ad1ebdbf 100644 --- a/boards/feather-m0/include/periph_conf.h +++ b/boards/feather-m0/include/periph_conf.h @@ -135,9 +135,6 @@ static const uart_conf_t uart_config[] = { } }; -/* interrupt function name mapping */ -#define UART_0_ISR isr_sercom0 - #define UART_NUMOF ARRAY_SIZE(uart_config) /** @} */ diff --git a/boards/samd10-xmini/include/periph_conf.h b/boards/samd10-xmini/include/periph_conf.h index 73ae58cc57f2..e81e30a9b5cb 100644 --- a/boards/samd10-xmini/include/periph_conf.h +++ b/boards/samd10-xmini/include/periph_conf.h @@ -139,9 +139,6 @@ static const uart_conf_t uart_config[] = { }, }; -/* interrupt function name mapping */ -#define UART_0_ISR isr_sercom0 - #define UART_NUMOF ARRAY_SIZE(uart_config) /** @} */ diff --git a/boards/samd20-xpro/include/periph_conf.h b/boards/samd20-xpro/include/periph_conf.h index 560e705fe2b0..c360fae1b495 100644 --- a/boards/samd20-xpro/include/periph_conf.h +++ b/boards/samd20-xpro/include/periph_conf.h @@ -138,8 +138,8 @@ static const tc32_conf_t timer_config[] = { static const uart_conf_t uart_config[] = { { /* Virtual COM Port */ .dev = &SERCOM3->USART, - .rx_pin = GPIO_PIN(PA,25), - .tx_pin = GPIO_PIN(PA,24), + .rx_pin = GPIO_PIN(PA, 25), + .tx_pin = GPIO_PIN(PA, 24), #ifdef MODULE_PERIPH_UART_HW_FC .rts_pin = GPIO_UNDEF, .cts_pin = GPIO_UNDEF, @@ -152,8 +152,8 @@ static const uart_conf_t uart_config[] = { }, { /* EXT1 */ .dev = &SERCOM4->USART, - .rx_pin = GPIO_PIN(PB,9), - .tx_pin = GPIO_PIN(PB,8), + .rx_pin = GPIO_PIN(PB, 9), + .tx_pin = GPIO_PIN(PB, 8), #ifdef MODULE_PERIPH_UART_HW_FC .rts_pin = GPIO_UNDEF, .cts_pin = GPIO_UNDEF, @@ -166,8 +166,8 @@ static const uart_conf_t uart_config[] = { }, { /* EXT2 */ .dev = &SERCOM0->USART, - .rx_pin = GPIO_PIN(PA,9), - .tx_pin = GPIO_PIN(PA,8), + .rx_pin = GPIO_PIN(PA, 9), + .tx_pin = GPIO_PIN(PA, 8), #ifdef MODULE_PERIPH_UART_HW_FC .rts_pin = GPIO_UNDEF, .cts_pin = GPIO_UNDEF, @@ -180,11 +180,6 @@ static const uart_conf_t uart_config[] = { }, }; -/* interrupt function name mapping */ -#define UART_0_ISR isr_sercom3 -#define UART_1_ISR isr_sercom4 -#define UART_2_ISR isr_sercom0 - #define UART_NUMOF ARRAY_SIZE(uart_config) /** @} */ diff --git a/boards/samd21-xpro/include/periph_conf.h b/boards/samd21-xpro/include/periph_conf.h index b3e7c494450d..9705f8bc1f2f 100644 --- a/boards/samd21-xpro/include/periph_conf.h +++ b/boards/samd21-xpro/include/periph_conf.h @@ -140,8 +140,8 @@ static const tc32_conf_t timer_config[] = { static const uart_conf_t uart_config[] = { { /* Virtual COM Port */ .dev = &SERCOM3->USART, - .rx_pin = GPIO_PIN(PA,23), - .tx_pin = GPIO_PIN(PA,22), + .rx_pin = GPIO_PIN(PA, 23), + .tx_pin = GPIO_PIN(PA, 22), #ifdef MODULE_PERIPH_UART_HW_FC .rts_pin = GPIO_UNDEF, .cts_pin = GPIO_UNDEF, @@ -154,8 +154,8 @@ static const uart_conf_t uart_config[] = { }, { /* EXT1 */ .dev = &SERCOM4->USART, - .rx_pin = GPIO_PIN(PB,9), - .tx_pin = GPIO_PIN(PB,8), + .rx_pin = GPIO_PIN(PB, 9), + .tx_pin = GPIO_PIN(PB, 8), #ifdef MODULE_PERIPH_UART_HW_FC .rts_pin = GPIO_UNDEF, .cts_pin = GPIO_UNDEF, @@ -168,8 +168,8 @@ static const uart_conf_t uart_config[] = { }, { /* EXT2/3 */ .dev = &SERCOM4->USART, - .rx_pin = GPIO_PIN(PB,11), - .tx_pin = GPIO_PIN(PB,10), + .rx_pin = GPIO_PIN(PB, 11), + .tx_pin = GPIO_PIN(PB, 10), #ifdef MODULE_PERIPH_UART_HW_FC .rts_pin = GPIO_UNDEF, .cts_pin = GPIO_UNDEF, @@ -182,11 +182,6 @@ static const uart_conf_t uart_config[] = { } }; -/* interrupt function name mapping */ -#define UART_0_ISR isr_sercom3 -#define UART_1_ISR isr_sercom4 -#define UART_2_ISR isr_sercom5 - #define UART_NUMOF ARRAY_SIZE(uart_config) /** @} */ diff --git a/boards/same54-xpro/include/periph_conf.h b/boards/same54-xpro/include/periph_conf.h index 8b208f8f0f37..70eff36409f6 100644 --- a/boards/same54-xpro/include/periph_conf.h +++ b/boards/same54-xpro/include/periph_conf.h @@ -182,19 +182,6 @@ static const uart_conf_t uart_config[] = { } }; -/* interrupt function name mapping */ -#define UART_0_ISR isr_sercom2_2 -#define UART_0_ISR_TX isr_sercom2_0 - -#define UART_1_ISR isr_sercom0_2 -#define UART_1_ISR_TX isr_sercom0_0 - -#define UART_2_ISR isr_sercom5_2 -#define UART_2_ISR_TX isr_sercom5_0 - -#define UART_3_ISR isr_sercom1_2 -#define UART_3_ISR_TX isr_sercom1_0 - #define UART_NUMOF ARRAY_SIZE(uart_config) /** @} */ diff --git a/boards/saml21-xpro/include/periph_conf.h b/boards/saml21-xpro/include/periph_conf.h index 4df72187314b..3ff3d0a0cc14 100644 --- a/boards/saml21-xpro/include/periph_conf.h +++ b/boards/saml21-xpro/include/periph_conf.h @@ -69,8 +69,8 @@ static const tc32_conf_t timer_config[] = { static const uart_conf_t uart_config[] = { { /* Virtual COM Port */ .dev = &SERCOM3->USART, - .rx_pin = GPIO_PIN(PA,23), - .tx_pin = GPIO_PIN(PA,22), + .rx_pin = GPIO_PIN(PA, 23), + .tx_pin = GPIO_PIN(PA, 22), #ifdef MODULE_PERIPH_UART_HW_FC .rts_pin = GPIO_UNDEF, .cts_pin = GPIO_UNDEF, @@ -111,11 +111,6 @@ static const uart_conf_t uart_config[] = { } }; -/* interrupt function name mapping */ -#define UART_0_ISR isr_sercom3 -#define UART_1_ISR isr_sercom4 -#define UART_2_ISR isr_sercom1 - #define UART_NUMOF ARRAY_SIZE(uart_config) /** @} */ diff --git a/boards/samr21-xpro/include/periph_conf.h b/boards/samr21-xpro/include/periph_conf.h index 72be389a056c..c3b9db602dd8 100644 --- a/boards/samr21-xpro/include/periph_conf.h +++ b/boards/samr21-xpro/include/periph_conf.h @@ -140,11 +140,11 @@ static const tc32_conf_t timer_config[] = { static const uart_conf_t uart_config[] = { { .dev = &SERCOM0->USART, - .rx_pin = GPIO_PIN(PA,5), - .tx_pin = GPIO_PIN(PA,4), + .rx_pin = GPIO_PIN(PA, 5), + .tx_pin = GPIO_PIN(PA, 4), #ifdef MODULE_PERIPH_UART_HW_FC - .rts_pin = GPIO_PIN(PA,6), - .cts_pin = GPIO_PIN(PA,7), + .rts_pin = GPIO_PIN(PA, 6), + .cts_pin = GPIO_PIN(PA, 7), #endif .mux = GPIO_MUX_D, .rx_pad = UART_PAD_RX_1, @@ -158,11 +158,11 @@ static const uart_conf_t uart_config[] = { }, { .dev = &SERCOM5->USART, - .rx_pin = GPIO_PIN(PA,23), - .tx_pin = GPIO_PIN(PA,22), + .rx_pin = GPIO_PIN(PA, 23), + .tx_pin = GPIO_PIN(PA, 22), #ifdef MODULE_PERIPH_UART_HW_FC - .rts_pin = GPIO_PIN(PB,22), - .cts_pin = GPIO_PIN(PB,23), + .rts_pin = GPIO_PIN(PB, 22), + .cts_pin = GPIO_PIN(PB, 23), #endif .mux = GPIO_MUX_D, .rx_pad = UART_PAD_RX_1, @@ -176,10 +176,6 @@ static const uart_conf_t uart_config[] = { } }; -/* interrupt function name mapping */ -#define UART_0_ISR isr_sercom0 -#define UART_1_ISR isr_sercom5 - #define UART_NUMOF ARRAY_SIZE(uart_config) /** @} */ diff --git a/boards/samr30-xpro/include/periph_conf.h b/boards/samr30-xpro/include/periph_conf.h index e27ce060670c..58015c89f104 100644 --- a/boards/samr30-xpro/include/periph_conf.h +++ b/boards/samr30-xpro/include/periph_conf.h @@ -59,8 +59,8 @@ static const tc32_conf_t timer_config[] = { static const uart_conf_t uart_config[] = { { /* Virtual COM Port */ .dev = &SERCOM0->USART, - .rx_pin = GPIO_PIN(PA,5), - .tx_pin = GPIO_PIN(PA,4), + .rx_pin = GPIO_PIN(PA, 5), + .tx_pin = GPIO_PIN(PA, 4), #ifdef MODULE_PERIPH_UART_HW_FC .rts_pin = GPIO_UNDEF, .cts_pin = GPIO_UNDEF, @@ -73,9 +73,6 @@ static const uart_conf_t uart_config[] = { } }; -/* interrupt function name mapping */ -#define UART_0_ISR isr_sercom0 - #define UART_NUMOF ARRAY_SIZE(uart_config) /** @} */ diff --git a/boards/samr34-xpro/include/periph_conf.h b/boards/samr34-xpro/include/periph_conf.h index 052d28187320..5fff0fd77238 100644 --- a/boards/samr34-xpro/include/periph_conf.h +++ b/boards/samr34-xpro/include/periph_conf.h @@ -106,10 +106,6 @@ static const uart_conf_t uart_config[] = { } }; -/* interrupt function name mapping */ -#define UART_0_ISR isr_sercom0 -#define UART_1_ISR isr_sercom3 - #define UART_NUMOF ARRAY_SIZE(uart_config) /** @} */ diff --git a/boards/seeeduino_xiao/include/periph_conf.h b/boards/seeeduino_xiao/include/periph_conf.h index 7d0ac748fc8b..e4ad1dbb3299 100644 --- a/boards/seeeduino_xiao/include/periph_conf.h +++ b/boards/seeeduino_xiao/include/periph_conf.h @@ -133,9 +133,6 @@ static const uart_conf_t uart_config[] = { } }; -/* interrupt function name mapping */ -#define UART_0_ISR isr_sercom4 - #define UART_NUMOF ARRAY_SIZE(uart_config) /** @} */ diff --git a/boards/sensebox_samd21/include/periph_conf.h b/boards/sensebox_samd21/include/periph_conf.h index a21d572b5285..caecb7dadc09 100644 --- a/boards/sensebox_samd21/include/periph_conf.h +++ b/boards/sensebox_samd21/include/periph_conf.h @@ -150,10 +150,6 @@ static const uart_conf_t uart_config[] = { } }; -/* interrupt function name mapping */ -#define UART_0_ISR isr_sercom3 -#define UART_1_ISR isr_sercom4 - #define UART_NUMOF ARRAY_SIZE(uart_config) /** @} */ diff --git a/boards/serpente/include/periph_conf.h b/boards/serpente/include/periph_conf.h index 289a1c9687a5..0720445f3a4a 100644 --- a/boards/serpente/include/periph_conf.h +++ b/boards/serpente/include/periph_conf.h @@ -141,10 +141,6 @@ static const uart_conf_t uart_config[] = { } }; -/* interrupt function name mapping */ -#define UART_0_ISR isr_sercom2 -#define UART_1_ISR isr_sercom0 - #define UART_NUMOF ARRAY_SIZE(uart_config) /** @} */ diff --git a/boards/sodaq-autonomo/include/periph_conf.h b/boards/sodaq-autonomo/include/periph_conf.h index 66127f3f73e2..bb384f20f76f 100644 --- a/boards/sodaq-autonomo/include/periph_conf.h +++ b/boards/sodaq-autonomo/include/periph_conf.h @@ -42,8 +42,8 @@ extern "C" { static const uart_conf_t uart_config[] = { { .dev = &SERCOM0->USART, - .rx_pin = GPIO_PIN(PA,9), - .tx_pin = GPIO_PIN(PA,10), + .rx_pin = GPIO_PIN(PA, 9), + .tx_pin = GPIO_PIN(PA, 10), #ifdef MODULE_PERIPH_UART_HW_FC .rts_pin = GPIO_UNDEF, .cts_pin = GPIO_UNDEF, @@ -56,8 +56,8 @@ static const uart_conf_t uart_config[] = { }, { .dev = &SERCOM5->USART, - .rx_pin = GPIO_PIN(PB,31), - .tx_pin = GPIO_PIN(PB,30), + .rx_pin = GPIO_PIN(PB, 31), + .tx_pin = GPIO_PIN(PB, 30), #ifdef MODULE_PERIPH_UART_HW_FC .rts_pin = GPIO_UNDEF, .cts_pin = GPIO_UNDEF, @@ -70,8 +70,8 @@ static const uart_conf_t uart_config[] = { }, { .dev = &SERCOM4->USART, - .rx_pin = GPIO_PIN(PB,13), - .tx_pin = GPIO_PIN(PB,14), + .rx_pin = GPIO_PIN(PB, 13), + .tx_pin = GPIO_PIN(PB, 14), #ifdef MODULE_PERIPH_UART_HW_FC .rts_pin = GPIO_UNDEF, .cts_pin = GPIO_UNDEF, @@ -84,8 +84,8 @@ static const uart_conf_t uart_config[] = { }, { .dev = &SERCOM1->USART, - .rx_pin = GPIO_PIN(PA,17), - .tx_pin = GPIO_PIN(PA,18), + .rx_pin = GPIO_PIN(PA, 17), + .tx_pin = GPIO_PIN(PA, 18), #ifdef MODULE_PERIPH_UART_HW_FC .rts_pin = GPIO_UNDEF, .cts_pin = GPIO_UNDEF, @@ -98,12 +98,6 @@ static const uart_conf_t uart_config[] = { }, }; -/* interrupt function name mapping */ -#define UART_0_ISR isr_sercom0 -#define UART_1_ISR isr_sercom5 -#define UART_2_ISR isr_sercom4 -#define UART_3_ISR isr_sercom1 - #define UART_NUMOF ARRAY_SIZE(uart_config) /** @} */ diff --git a/boards/sodaq-explorer/include/periph_conf.h b/boards/sodaq-explorer/include/periph_conf.h index 117532fa0826..a803cbbe0b88 100644 --- a/boards/sodaq-explorer/include/periph_conf.h +++ b/boards/sodaq-explorer/include/periph_conf.h @@ -38,8 +38,8 @@ extern "C" { static const uart_conf_t uart_config[] = { { .dev = &SERCOM5->USART, - .rx_pin = GPIO_PIN(PB,31), /* D0, RX Pin */ - .tx_pin = GPIO_PIN(PB,30), /* D1, TX Pin */ + .rx_pin = GPIO_PIN(PB, 31), /* D0, RX Pin */ + .tx_pin = GPIO_PIN(PB, 30), /* D1, TX Pin */ #ifdef MODULE_PERIPH_UART_HW_FC .rts_pin = GPIO_UNDEF, .cts_pin = GPIO_UNDEF, @@ -52,8 +52,8 @@ static const uart_conf_t uart_config[] = { }, { .dev = &SERCOM4->USART, - .rx_pin = GPIO_PIN(PB,13), - .tx_pin = GPIO_PIN(PB,14), + .rx_pin = GPIO_PIN(PB, 13), + .tx_pin = GPIO_PIN(PB, 14), #ifdef MODULE_PERIPH_UART_HW_FC .rts_pin = GPIO_UNDEF, .cts_pin = GPIO_UNDEF, @@ -66,8 +66,8 @@ static const uart_conf_t uart_config[] = { }, { /* Connected to RN2483 */ .dev = &SERCOM0->USART, - .rx_pin = GPIO_PIN(PA,5), - .tx_pin = GPIO_PIN(PA,6), + .rx_pin = GPIO_PIN(PA, 5), + .tx_pin = GPIO_PIN(PA, 6), #ifdef MODULE_PERIPH_UART_HW_FC .rts_pin = GPIO_UNDEF, .cts_pin = GPIO_UNDEF, @@ -80,11 +80,6 @@ static const uart_conf_t uart_config[] = { }, }; -/* interrupt function name mapping */ -#define UART_0_ISR isr_sercom5 -#define UART_1_ISR isr_sercom4 -#define UART_2_ISR isr_sercom0 - #define UART_NUMOF ARRAY_SIZE(uart_config) /** @} */ diff --git a/boards/sodaq-one/include/periph_conf.h b/boards/sodaq-one/include/periph_conf.h index e9af038fd560..974dea4511db 100644 --- a/boards/sodaq-one/include/periph_conf.h +++ b/boards/sodaq-one/include/periph_conf.h @@ -41,8 +41,8 @@ extern "C" { static const uart_conf_t uart_config[] = { { .dev = &SERCOM5->USART, - .rx_pin = GPIO_PIN(PB,3), /* D0, RX Pin */ - .tx_pin = GPIO_PIN(PB,2), /* D1, TX Pin */ + .rx_pin = GPIO_PIN(PB, 3), /* D0, RX Pin */ + .tx_pin = GPIO_PIN(PB, 2), /* D1, TX Pin */ #ifdef MODULE_PERIPH_UART_HW_FC .rts_pin = GPIO_UNDEF, .cts_pin = GPIO_UNDEF, @@ -55,8 +55,8 @@ static const uart_conf_t uart_config[] = { }, { .dev = &SERCOM2->USART, - .rx_pin = GPIO_PIN(PA,13), - .tx_pin = GPIO_PIN(PA,12), + .rx_pin = GPIO_PIN(PA, 13), + .tx_pin = GPIO_PIN(PA, 12), #ifdef MODULE_PERIPH_UART_HW_FC .rts_pin = GPIO_UNDEF, .cts_pin = GPIO_UNDEF, @@ -69,10 +69,6 @@ static const uart_conf_t uart_config[] = { }, }; -/* interrupt function name mapping */ -#define UART_0_ISR isr_sercom5 -#define UART_1_ISR isr_sercom2 - #define UART_NUMOF ARRAY_SIZE(uart_config) /** @} */ diff --git a/boards/sodaq-sara-aff/include/periph_conf.h b/boards/sodaq-sara-aff/include/periph_conf.h index f53eccc048b2..fd68f3adb327 100644 --- a/boards/sodaq-sara-aff/include/periph_conf.h +++ b/boards/sodaq-sara-aff/include/periph_conf.h @@ -58,8 +58,8 @@ static const uart_conf_t uart_config[] = { }, { .dev = &SERCOM0->USART, - .rx_pin = GPIO_PIN(PA,5), - .tx_pin = GPIO_PIN(PA,6), + .rx_pin = GPIO_PIN(PA, 5), + .tx_pin = GPIO_PIN(PA, 6), #ifdef MODULE_PERIPH_UART_HW_FC .rts_pin = GPIO_UNDEF, .cts_pin = GPIO_UNDEF, @@ -72,10 +72,6 @@ static const uart_conf_t uart_config[] = { }, }; -/* interrupt function name mapping */ -#define UART_0_ISR isr_sercom5 -#define UART_1_ISR isr_sercom0 - #define UART_NUMOF ARRAY_SIZE(uart_config) /** @} */ diff --git a/boards/sodaq-sara-sff/include/periph_conf.h b/boards/sodaq-sara-sff/include/periph_conf.h index 0b3216aef08d..ac26f2124739 100644 --- a/boards/sodaq-sara-sff/include/periph_conf.h +++ b/boards/sodaq-sara-sff/include/periph_conf.h @@ -69,10 +69,6 @@ static const uart_conf_t uart_config[] = { }, }; -/* interrupt function name mapping */ -#define UART_0_ISR isr_sercom5 -#define UART_1_ISR isr_sercom2 - #define UART_NUMOF ARRAY_SIZE(uart_config) /** @} */ diff --git a/boards/yarm/include/periph_conf.h b/boards/yarm/include/periph_conf.h index aee2428f65ed..25774eb23290 100644 --- a/boards/yarm/include/periph_conf.h +++ b/boards/yarm/include/periph_conf.h @@ -80,9 +80,6 @@ static const uart_conf_t uart_config[] = { } }; -/* interrupt function name mapping */ -#define UART_0_ISR isr_sercom3 - #define UART_NUMOF ARRAY_SIZE(uart_config) /** @} */ diff --git a/bootloaders/riotboot_serial/Makefile.ci b/bootloaders/riotboot_serial/Makefile.ci index f77aecd2a53d..b3258d277327 100644 --- a/bootloaders/riotboot_serial/Makefile.ci +++ b/bootloaders/riotboot_serial/Makefile.ci @@ -2,5 +2,6 @@ BOARD_INSUFFICIENT_MEMORY := \ frdm-kw41z \ pba-d-01-kw2x \ phynode-kw41z \ + samr21-xpro \ usb-kw41z \ # diff --git a/cpu/sam0_common/Makefile.dep b/cpu/sam0_common/Makefile.dep index 199b1c9f5bdd..62095d6edcdd 100644 --- a/cpu/sam0_common/Makefile.dep +++ b/cpu/sam0_common/Makefile.dep @@ -10,6 +10,11 @@ ifneq (,$(filter periph_spi,$(USEMODULE))) USEMODULE += periph_spi_gpio_mode endif +ifneq (,$(filter periph_spi periph_uart periph_i2c,$(USEMODULE))) + FEATURES_REQUIRED += periph_sercom + USEMODULE += bitfield +endif + ifneq (,$(filter periph_sdmmc,$(USEMODULE))) USEMODULE += sdmmc_sdhc endif diff --git a/cpu/sam0_common/Makefile.features b/cpu/sam0_common/Makefile.features index 17a745166a9b..f86a54249a01 100644 --- a/cpu/sam0_common/Makefile.features +++ b/cpu/sam0_common/Makefile.features @@ -30,6 +30,7 @@ FEATURES_PROVIDED += periph_sdmmc_auto_cmd12 FEATURES_PROVIDED += periph_sdmmc_hs FEATURES_PROVIDED += periph_sdmmc_mmc FEATURES_PROVIDED += periph_sdmmc_sdhc +FEATURES_PROVIDED += periph_sercom FEATURES_PROVIDED += periph_spi_reconfigure FEATURES_PROVIDED += periph_spi_gpio_mode FEATURES_PROVIDED += periph_spi_reconfigure diff --git a/cpu/sam0_common/include/cpu_conf.h b/cpu/sam0_common/include/cpu_conf.h index dd697e8e37b4..515e2ac346f0 100644 --- a/cpu/sam0_common/include/cpu_conf.h +++ b/cpu/sam0_common/include/cpu_conf.h @@ -21,40 +21,40 @@ #ifndef CPU_CONF_H #define CPU_CONF_H -#include "cpu_conf_common.h" +#include "cpu_conf_common.h" /* IWYU pragma: export */ #if defined(CPU_SAMD10) -#include "vendor/samd10/include/samd10.h" +#include "vendor/samd10/include/samd10.h" /* IWYU pragma: export */ #elif defined(CPU_SAMD20) -#include "vendor/samd20/include/samd20.h" +#include "vendor/samd20/include/samd20.h" /* IWYU pragma: export */ #elif defined(CPU_SAMD20B) -#include "vendor/samd20/include_b/samd20.h" +#include "vendor/samd20/include_b/samd20.h" /* IWYU pragma: export */ #elif defined(CPU_SAMD21A) -#include "vendor/samd21/include_a/samd21.h" +#include "vendor/samd21/include_a/samd21.h" /* IWYU pragma: export */ #elif defined(CPU_SAMD21B) -#include "vendor/samd21/include_b/samd21.h" +#include "vendor/samd21/include_b/samd21.h" /* IWYU pragma: export */ #elif defined(CPU_SAMD21C) -#include "vendor/samd21/include_c/samd21.h" +#include "vendor/samd21/include_c/samd21.h" /* IWYU pragma: export */ #elif defined(CPU_SAMD21D) -#include "vendor/samd21/include_d/samd21.h" +#include "vendor/samd21/include_d/samd21.h" /* IWYU pragma: export */ #elif defined(CPU_SAMD51) -#include "vendor/samd51/include/samd51.h" +#include "vendor/samd51/include/samd51.h" /* IWYU pragma: export */ #elif defined(CPU_SAME54) -#include "vendor/same54/include/same54.h" +#include "vendor/same54/include/same54.h" /* IWYU pragma: export */ #elif defined(CPU_SAML10) -#include "vendor/saml10/include/sam.h" +#include "vendor/saml10/include/sam.h" /* IWYU pragma: export */ #elif defined(CPU_SAML11) -#include "vendor/saml11/include/sam.h" +#include "vendor/saml11/include/sam.h" /* IWYU pragma: export */ #elif defined(CPU_SAML21A) -#include "vendor/saml21/include/saml21.h" +#include "vendor/saml21/include/saml21.h" /* IWYU pragma: export */ #elif defined(CPU_SAML21B) -#include "vendor/saml21/include_b/saml21.h" +#include "vendor/saml21/include_b/saml21.h" /* IWYU pragma: export */ #elif defined(CPU_SAMR21) -#include "vendor/samr21/include/samr21.h" +#include "vendor/samr21/include/samr21.h" /* IWYU pragma: export */ #elif defined(CPU_SAMR30) -#include "vendor/samr30/include/samr30.h" +#include "vendor/samr30/include/samr30.h" /* IWYU pragma: export */ #elif defined(CPU_SAMR34) -#include "vendor/samr34/include/samr34.h" +#include "vendor/samr34/include/samr34.h" /* IWYU pragma: export */ #endif #ifdef __cplusplus diff --git a/cpu/sam0_common/include/periph_cpu_common.h b/cpu/sam0_common/include/periph_cpu_common.h index dd8be928de9a..18e032f9b5af 100644 --- a/cpu/sam0_common/include/periph_cpu_common.h +++ b/cpu/sam0_common/include/periph_cpu_common.h @@ -316,6 +316,76 @@ typedef enum { #endif /* ndef DOXYGEN */ +/** + * @name Common SERCOM Interface + * @{ + */ +/** + * @brief Identifier of a SERCOM + */ +typedef uint8_t sercom_t; + +/** + * @brief IRQ callback to call on IRQs triggered by the SERCOM + * + * @param[in] arg The argument provided on @ref sercom_acquire + */ +typedef void (*sercom_irq_cb_t)(void *arg); + +/** + * @brief Acquire exclusive access to the given SERCOM, enable it, and + * configure it as specified + * @param[in] sercom The SERCOM to acquire + * @param[in] gclk Generator clock + * @param[in] irq_cb Function to call on IRQ or `NULL` + * @param[in] irq_arg Argument to pass to @p irq_cb + * + * @note This function may block if the SERCOM is already in use to provide + * another serial interface until it is release. + * @warning Beware: UART buses are typically kept acquired and never released. + * + * @pre The pins the caller wants to route to the SERCOM are not routed to + * it prior to the call (as the SERCOM may still be active). Only + * after this function returns, pins may be routed to the SERCOM. + * @post The SERCOM is exclusively held by the caller + * @post The SERCOM is configured as asked for in @p conf + * @post If @p irq_cb was `NULL`, the corresponding IRQ(s) is/are disabled + * in the NIVC. Otherwise they are enabled but masked. + */ +void sercom_acquire(sercom_t sercom, uint8_t gclk, + sercom_irq_cb_t irq_cb, void *irq_arg); + +/** + * @brief Enable the SERCOM APB clock + * @param[in] sercom The SERCOM to enable the clock of + */ +static inline void sercom_apb_enable(sercom_t sercom); + +/** + * @brief Disable the SERCOM APB clock + * @param[in] sercom The SERCOM to disable the clock of + */ +static inline void sercom_apb_disable(sercom_t sercom); + +/** + * @brief Enable GCLK clock signal to the given SEROM + * @param[in] sercom The SERCOM to clock + * @param[in] gclk Generator clock + */ +static inline void sercom_gclk_enable(sercom_t sercom, uint8_t gclk); + +/** + * @brief Release exclusive access to the given SERCOM and disable it + * (low power mode) + * @param[in] sercom The SERCOM to release + * + * @pre The pins that were routed to this SERCOM are no longer routed to it, + * so that other pins can be routed to it right after the SERCOM is + * release to provide other serial buses + */ +void sercom_release(sercom_t sercom); +/** @} */ + /** * @brief Size of the UART TX buffer for non-blocking mode. */ @@ -433,6 +503,15 @@ typedef struct { uint8_t gclk_src; /**< GCLK source which clocks TIMER */ } pwm_conf_t; +/** + * @brief Special SERCOM ID to identify the QSPI + * + * When module `periph_spi_on_qspi` is used, we need to identify in the SPI + * config that the SPI is not implemented using a SERCOM but using a QSPI + * peripheral. This magic invalid SERCOM id is to be used for that. + */ +#define SERCOM_ID_QSPI 0xff + /** * @brief Available values for SERCOM SPI MISO pad selection */ @@ -505,7 +584,7 @@ typedef struct { gpio_mux_t clk_mux; /**< alternate function for CLK pin (mux) */ spi_misopad_t miso_pad; /**< pad to use for MISO line */ spi_mosipad_t mosi_pad; /**< pad to use for MOSI and CLK line */ - uint8_t gclk_src; /**< GCLK source which supplys SERCOM */ + uint8_t gclk_src; /**< GCLK source which supplies SERCOM */ #ifdef MODULE_PERIPH_DMA uint8_t tx_trigger; /**< DMA trigger */ uint8_t rx_trigger; /**< DMA trigger */ @@ -564,7 +643,7 @@ typedef struct { gpio_t scl_pin; /**< used SCL pin */ gpio_t sda_pin; /**< used MOSI pin */ gpio_mux_t mux; /**< alternate function (mux) */ - uint8_t gclk_src; /**< GCLK source which supplys SERCOM */ + uint8_t gclk_src; /**< GCLK source which suppliess SERCOM */ uint8_t flags; /**< allow SERCOM to run in standby mode */ } i2c_conf_t; @@ -766,66 +845,6 @@ static inline uint8_t sercom_id(const void *sercom) return SERCOM_INST_NUM; } -/** - * @brief Enable peripheral clock for given SERCOM device - * - * @param[in] sercom SERCOM device - */ -static inline void sercom_clk_en(void *sercom) -{ - const uint8_t id = sercom_id(sercom); -#if defined(CPU_COMMON_SAMD21) - PM->APBCMASK.reg |= (PM_APBCMASK_SERCOM0 << id); -#elif defined (CPU_COMMON_SAMD5X) - if (id < 2) { - MCLK->APBAMASK.reg |= (1 << (id + 12)); - } else if (id < 4) { - MCLK->APBBMASK.reg |= (1 << (id + 7)); - } else { - MCLK->APBDMASK.reg |= (1 << (id - 4)); - } -#else - if (id < 5) { - MCLK->APBCMASK.reg |= (MCLK_APBCMASK_SERCOM0 << id); - } -#if defined(CPU_COMMON_SAML21) - else { - MCLK->APBDMASK.reg |= (MCLK_APBDMASK_SERCOM5); - } -#endif /* CPU_COMMON_SAML21 */ -#endif -} - -/** - * @brief Disable peripheral clock for given SERCOM device - * - * @param[in] sercom SERCOM device - */ -static inline void sercom_clk_dis(void *sercom) -{ - const uint8_t id = sercom_id(sercom); -#if defined(CPU_COMMON_SAMD21) - PM->APBCMASK.reg &= ~(PM_APBCMASK_SERCOM0 << id); -#elif defined (CPU_COMMON_SAMD5X) - if (id < 2) { - MCLK->APBAMASK.reg &= ~(1 << (id + 12)); - } else if (id < 4) { - MCLK->APBBMASK.reg &= ~(1 << (id + 7)); - } else { - MCLK->APBDMASK.reg &= ~(1 << (id - 4)); - } -#else - if (id < 5) { - MCLK->APBCMASK.reg &= ~(MCLK_APBCMASK_SERCOM0 << id); - } -#if defined (CPU_COMMON_SAML21) - else { - MCLK->APBDMASK.reg &= ~(MCLK_APBDMASK_SERCOM5); - } -#endif /* CPU_COMMON_SAML21 */ -#endif -} - #ifdef CPU_COMMON_SAMD5X static inline uint8_t _sercom_gclk_id_core(uint8_t sercom_id) { if (sercom_id < 2) { diff --git a/cpu/sam0_common/include/vendor/samd51/include/samd51.h b/cpu/sam0_common/include/vendor/samd51/include/samd51.h index e8aa58d2ca04..1cad67595d80 100644 --- a/cpu/sam0_common/include/vendor/samd51/include/samd51.h +++ b/cpu/sam0_common/include/vendor/samd51/include/samd51.h @@ -14,9 +14,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. * You may obtain a copy of the Licence at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an AS IS BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -36,27 +36,27 @@ */ #if defined(__SAMD51G18A__) || defined(__ATSAMD51G18A__) - #include "samd51g18a.h" + #include "samd51g18a.h" /* IWYU pragma: export */ #elif defined(__SAMD51G19A__) || defined(__ATSAMD51G19A__) - #include "samd51g19a.h" + #include "samd51g19a.h" /* IWYU pragma: export */ #elif defined(__SAMD51J18A__) || defined(__ATSAMD51J18A__) - #include "samd51j18a.h" + #include "samd51j18a.h" /* IWYU pragma: export */ #elif defined(__SAMD51J19A__) || defined(__ATSAMD51J19A__) - #include "samd51j19a.h" + #include "samd51j19a.h" /* IWYU pragma: export */ #elif defined(__SAMD51J19B__) || defined(__ATSAMD51J19B__) - #include "samd51j19b.h" + #include "samd51j19b.h" /* IWYU pragma: export */ #elif defined(__SAMD51J20A__) || defined(__ATSAMD51J20A__) - #include "samd51j20a.h" + #include "samd51j20a.h" /* IWYU pragma: export */ #elif defined(__SAMD51J20C__) || defined(__ATSAMD51J20C__) - #include "samd51j20c.h" + #include "samd51j20c.h" /* IWYU pragma: export */ #elif defined(__SAMD51N19A__) || defined(__ATSAMD51N19A__) - #include "samd51n19a.h" + #include "samd51n19a.h" /* IWYU pragma: export */ #elif defined(__SAMD51N20A__) || defined(__ATSAMD51N20A__) - #include "samd51n20a.h" + #include "samd51n20a.h" /* IWYU pragma: export */ #elif defined(__SAMD51P19A__) || defined(__ATSAMD51P19A__) - #include "samd51p19a.h" + #include "samd51p19a.h" /* IWYU pragma: export */ #elif defined(__SAMD51P20A__) || defined(__ATSAMD51P20A__) - #include "samd51p20a.h" + #include "samd51p20a.h" /* IWYU pragma: export */ #else #error Library does not support the specified device. #endif diff --git a/cpu/sam0_common/periph/i2c.c b/cpu/sam0_common/periph/i2c.c index 2772ccec65ac..55893deda8d6 100644 --- a/cpu/sam0_common/periph/i2c.c +++ b/cpu/sam0_common/periph/i2c.c @@ -26,19 +26,14 @@ #include #include -#include "cpu.h" -#include "board.h" #include "mutex.h" #include "periph_conf.h" #include "periph/i2c.h" -#include "sched.h" -#include "thread.h" - #define ENABLE_DEBUG 0 #include "debug.h" -#define SAMD21_I2C_TIMEOUT (65535) +#define SAM0_I2C_TIMEOUT (65535) #define BUSSTATE_UNKNOWN SERCOM_I2CM_STATUS_BUSSTATE(0) #define BUSSTATE_IDLE SERCOM_I2CM_STATUS_BUSSTATE(1) @@ -57,20 +52,24 @@ static inline int _read(SercomI2cm *dev, uint8_t *data, size_t length, static inline void _stop(SercomI2cm *dev); static inline int _wait_for_response(SercomI2cm *dev, uint32_t max_timeout_counter); -static void _i2c_poweron(i2c_t dev); -static void _i2c_poweroff(i2c_t dev); +static void _i2c_poweron(SercomI2cm *dev); /** - * @brief Array holding one pre-initialized mutex for each I2C device + * @brief Array holding one pre-initialized mutex for each pair I2C pins */ static mutex_t locks[I2C_NUMOF]; - /** - * @brief Shortcut for accessing the used I2C SERCOM device + * @brief Cache the configuration for faster SERCOM initialization */ -static inline SercomI2cm *bus(i2c_t dev) +static struct i2c_sercom_config { + uint32_t ctrla; /**< This goes into the CTRLA register */ + uint32_t ctrlb; /**< This goes into the CTRLB register */ + uint32_t baud; /**< This goes into the BAUD register */ +} _configs[I2C_NUMOF]; + +static SercomI2cm *_dev(i2c_t bus) { - return i2c_config[dev].dev; + return i2c_config[bus].dev; } static void _syncbusy(SercomI2cm *dev) @@ -82,81 +81,52 @@ static void _syncbusy(SercomI2cm *dev) #endif } -static void _reset(SercomI2cm *dev) +static void _attach_pins(i2c_t dev) { - dev->CTRLA.reg |= SERCOM_SPI_CTRLA_SWRST; - while (dev->CTRLA.reg & SERCOM_SPI_CTRLA_SWRST) {} + gpio_init_mux(i2c_config[dev].sda_pin, i2c_config[dev].mux); + gpio_init_mux(i2c_config[dev].scl_pin, i2c_config[dev].mux); +} -#ifdef SERCOM_I2CM_STATUS_SYNCBUSY - while (dev->STATUS.reg & SERCOM_I2CM_STATUS_SYNCBUSY) {} -#else - while (dev->SYNCBUSY.reg & SERCOM_I2CM_SYNCBUSY_SWRST) {} -#endif +static void _detach_pins(i2c_t dev) +{ + gpio_disable_mux(i2c_config[dev].sda_pin); + gpio_disable_mux(i2c_config[dev].scl_pin); } -void i2c_init(i2c_t dev) +void i2c_init(i2c_t bus) { - uint32_t timeout_counter = 0; int32_t tmp_baud; - assert(dev < I2C_NUMOF); + assert(bus < I2C_NUMOF); - const uint32_t fSCL = i2c_config[dev].speed; - const uint32_t fGCLK = sam0_gclk_freq(i2c_config[dev].gclk_src); + const uint32_t fSCL = i2c_config[bus].speed; + const uint32_t fGCLK = sam0_gclk_freq(i2c_config[bus].gclk_src); /* Initialize mutex */ - mutex_init(&locks[dev]); - - /* DISABLE I2C MASTER */ - _i2c_poweroff(dev); - - /* Reset I2C */ - _reset(bus(dev)); - - /* Turn on power manager for sercom */ - sercom_clk_en(bus(dev)); - - /* I2C using CLK GEN 0 */ - sercom_set_gen(bus(dev), i2c_config[dev].gclk_src); - - /* Check if module is enabled. */ - if (bus(dev)->CTRLA.reg & SERCOM_I2CM_CTRLA_ENABLE) { - DEBUG("STATUS_ERR_DENIED\n"); - return; - } - /* Check if reset is in progress. */ - if (bus(dev)->CTRLA.reg & SERCOM_I2CM_CTRLA_SWRST) { - DEBUG("STATUS_BUSY\n"); - return; - } - - /************ SERCOM PAD0 - SDA and SERCOM PAD1 - SCL *************/ - gpio_init_mux(i2c_config[dev].sda_pin, i2c_config[dev].mux); - gpio_init_mux(i2c_config[dev].scl_pin, i2c_config[dev].mux); - - /* I2C CONFIGURATION */ - _syncbusy(bus(dev)); + mutex_init(&locks[bus]); /* Set sercom module to operate in I2C master mode and run in Standby if user requests it */ - bus(dev)->CTRLA.reg = SERCOM_I2CM_CTRLA_MODE_I2C_MASTER - | ((i2c_config[dev].flags & I2C_FLAG_RUN_STANDBY) ? + _configs[bus].ctrla = SERCOM_I2CM_CTRLA_MODE_I2C_MASTER + | ((i2c_config[bus].flags & I2C_FLAG_RUN_STANDBY) ? SERCOM_I2CM_CTRLA_RUNSTDBY : 0); /* Enable Smart Mode (ACK is sent when DATA.DATA is read) */ - bus(dev)->CTRLB.reg = SERCOM_I2CM_CTRLB_SMEN; + _configs[bus].ctrlb = SERCOM_I2CM_CTRLB_SMEN; /* Set SPEED */ #ifdef SERCOM_I2CM_CTRLA_SPEED /* > 1000 kHz */ if (fSCL > I2C_SPEED_FAST_PLUS) { - bus(dev)->CTRLA.reg |= SERCOM_I2CM_CTRLA_SPEED(2); + _configs[bus].ctrla |= SERCOM_I2CM_CTRLA_SPEED(2); /* > 400 kHz */ - } else if (fSCL > I2C_SPEED_FAST) { - bus(dev)->CTRLA.reg |= SERCOM_I2CM_CTRLA_SPEED(1); + } + else if (fSCL > I2C_SPEED_FAST) { + _configs[bus].ctrla |= SERCOM_I2CM_CTRLA_SPEED(1); /* ≤ 400 kHz */ - } else { - bus(dev)->CTRLA.reg |= SERCOM_I2CM_CTRLA_SPEED(0); + } + else { + _configs[bus].ctrla |= SERCOM_I2CM_CTRLA_SPEED(0); } #else assert(fSCL < I2C_SPEED_FAST_PLUS); @@ -174,68 +144,74 @@ void i2c_init(i2c_t dev) #ifdef SERCOM_I2CM_BAUD_HSBAUD if (fSCL > I2C_SPEED_FAST_PLUS) { - bus(dev)->BAUD.reg = SERCOM_I2CM_BAUD_HSBAUD(tmp_baud); - } else + _configs[bus].baud = SERCOM_I2CM_BAUD_HSBAUD(tmp_baud); + } + else #endif { - bus(dev)->BAUD.reg = SERCOM_I2CM_BAUD_BAUD(tmp_baud); + _configs[bus].baud = SERCOM_I2CM_BAUD_BAUD(tmp_baud); } +} - /* ENABLE I2C MASTER */ +void i2c_acquire(i2c_t bus) +{ + assert(bus < I2C_NUMOF); + sercom_t sercom = sercom_id(i2c_config[bus].dev); + SercomI2cm *dev = _dev(bus); + + mutex_lock(&locks[bus]); + sercom_acquire(sercom, i2c_config[bus].gclk_src, NULL, NULL); + dev->BAUD.reg = _configs[bus].baud; + dev->CTRLA.reg = _configs[bus].ctrla; + dev->CTRLB.reg = _configs[bus].ctrlb; + _attach_pins(bus); _i2c_poweron(dev); - /* Start timeout if bus state is unknown. */ - while ((bus(dev)->STATUS.reg & - SERCOM_I2CM_STATUS_BUSSTATE_Msk) == BUSSTATE_UNKNOWN) { - if (timeout_counter++ >= SAMD21_I2C_TIMEOUT) { - /* Timeout, force bus state to idle. */ - bus(dev)->STATUS.reg = BUSSTATE_IDLE; - } + /* Force bus to IDLE state: At least on SAMD21 the SERCOM will stick in + * unknown state and never recover. Adding a timeout here would make + * I2C too slow to be sensible. */ + while (dev->STATUS.reg != BUSSTATE_IDLE) { + dev->STATUS.reg = BUSSTATE_IDLE; + _syncbusy(dev); } -} -void i2c_acquire(i2c_t dev) -{ - assert(dev < I2C_NUMOF); - mutex_lock(&locks[dev]); + DEBUG("[i2c] acquired I2C%u on SERCOM%u: CTRLA=%x, CTRLB=%x, BAUD=%x, STATUS=%x\n", + (unsigned)bus, (unsigned)sercom, + (unsigned)dev->CTRLA.reg, (unsigned)dev->CTRLB.reg, + (unsigned)dev->BAUD.reg, (unsigned)dev->STATUS.reg); } -void i2c_release(i2c_t dev) +void i2c_release(i2c_t bus) { - assert(dev < I2C_NUMOF); - mutex_unlock(&locks[dev]); + assert(bus < I2C_NUMOF); + sercom_t sercom = sercom_id(i2c_config[bus].dev); + DEBUG("[i2c] releasing #%u on SERCOM%u\n", (unsigned)bus, (unsigned)sercom); + _detach_pins(bus); + sercom_release(sercom); + mutex_unlock(&locks[bus]); } #ifdef MODULE_PERIPH_I2C_RECONFIGURE -void i2c_init_pins(i2c_t dev) +void i2c_init_pins(i2c_t bus) { - assert(dev < I2C_NUMOF); - - _i2c_poweron(dev); - - gpio_init_mux(i2c_config[dev].scl_pin, i2c_config[dev].mux); - gpio_init_mux(i2c_config[dev].sda_pin, i2c_config[dev].mux); - - mutex_unlock(&locks[dev]); + assert(bus < I2C_NUMOF); + mutex_unlock(&locks[bus]); } -void i2c_deinit_pins(i2c_t dev) +void i2c_deinit_pins(i2c_t bus) { - assert(dev < I2C_NUMOF); + assert(bus < I2C_NUMOF); - mutex_lock(&locks[dev]); - _i2c_poweroff(dev); - - gpio_disable_mux(i2c_config[dev].sda_pin); - gpio_disable_mux(i2c_config[dev].scl_pin); + mutex_lock(&locks[bus]); } #endif -int i2c_read_bytes(i2c_t dev, uint16_t addr, +int i2c_read_bytes(i2c_t bus, uint16_t addr, void *data, size_t len, uint8_t flags) { int ret; - assert(dev < I2C_NUMOF); + assert(bus < I2C_NUMOF); + SercomI2cm *dev = _dev(bus); /* Check for unsupported operations */ if (flags & I2C_ADDR10) { @@ -248,36 +224,37 @@ int i2c_read_bytes(i2c_t dev, uint16_t addr, if (!(flags & I2C_NOSTART)) { /* start transmission and send slave address */ - ret = _i2c_start(bus(dev), (addr << 1) | I2C_READ); + ret = _i2c_start(dev, (addr << 1) | I2C_READ); if (ret < 0) { DEBUG("Start command failed\n"); return ret; } } /* read data to register and issue stop if needed */ - ret = _read(bus(dev), data, len, (flags & I2C_NOSTOP) ? 0 : 1); + ret = _read(dev, data, len, (flags & I2C_NOSTOP) ? 0 : 1); if (ret < 0) { DEBUG("Read command failed\n"); return ret; } /* Ensure all bytes has been read */ if (flags & I2C_NOSTOP) { - while ((bus(dev)->STATUS.reg & SERCOM_I2CM_STATUS_BUSSTATE_Msk) + while ((dev->STATUS.reg & SERCOM_I2CM_STATUS_BUSSTATE_Msk) != BUSSTATE_OWNER) {} } else { - while ((bus(dev)->STATUS.reg & SERCOM_I2CM_STATUS_BUSSTATE_Msk) + while ((dev->STATUS.reg & SERCOM_I2CM_STATUS_BUSSTATE_Msk) != BUSSTATE_IDLE) {} } /* return number of bytes sent */ return 0; } -int i2c_write_bytes(i2c_t dev, uint16_t addr, const void *data, size_t len, +int i2c_write_bytes(i2c_t bus, uint16_t addr, const void *data, size_t len, uint8_t flags) { int ret; - assert(dev < I2C_NUMOF); + assert(bus < I2C_NUMOF); + SercomI2cm *dev = _dev(bus); /* Check for unsupported operations */ if (flags & I2C_ADDR10) { @@ -289,13 +266,13 @@ int i2c_write_bytes(i2c_t dev, uint16_t addr, const void *data, size_t len, } if (!(flags & I2C_NOSTART)) { - ret = _i2c_start(bus(dev), (addr<<1)); + ret = _i2c_start(dev, (addr << 1)); if (ret < 0) { DEBUG("Start command failed\n"); return ret; } } - ret = _write(bus(dev), data, len, (flags & I2C_NOSTOP) ? 0 : 1); + ret = _write(dev, data, len, (flags & I2C_NOSTOP) ? 0 : 1); if (ret < 0) { DEBUG("Write command failed\n"); return ret; @@ -304,26 +281,10 @@ int i2c_write_bytes(i2c_t dev, uint16_t addr, const void *data, size_t len, return 0; } -void _i2c_poweron(i2c_t dev) +static void _i2c_poweron(SercomI2cm *dev) { - assert(dev < I2C_NUMOF); - - if (bus(dev) == NULL) { - return; - } - bus(dev)->CTRLA.reg |= SERCOM_I2CM_CTRLA_ENABLE; - _syncbusy(bus(dev)); -} - -void _i2c_poweroff(i2c_t dev) -{ - assert(dev < I2C_NUMOF); - - if (bus(dev) == NULL) { - return; - } - bus(dev)->CTRLA.reg &= ~SERCOM_I2CM_CTRLA_ENABLE; - _syncbusy(bus(dev)); + dev->CTRLA.reg |= SERCOM_I2CM_CTRLA_ENABLE; + _syncbusy(dev); } static int _i2c_start(SercomI2cm *dev, uint16_t addr) @@ -343,12 +304,14 @@ static int _i2c_start(SercomI2cm *dev, uint16_t addr) if (addr & I2C_READ) { /* Some devices (e.g. SHT2x) can hold the bus while preparing the reply */ - if (_wait_for_response(dev, 100 * SAMD21_I2C_TIMEOUT) < 0) + if (_wait_for_response(dev, 100 * SAM0_I2C_TIMEOUT) < 0) { return -ETIMEDOUT; + } } else { - if (_wait_for_response(dev, SAMD21_I2C_TIMEOUT) < 0) + if (_wait_for_response(dev, SAM0_I2C_TIMEOUT) < 0) { return -ETIMEDOUT; + } } /* Check for address response error unless previous error is detected. */ @@ -396,7 +359,7 @@ static inline int _write(SercomI2cm *dev, const uint8_t *data, size_t length, dev->DATA.reg = data[count++]; /* Wait for response on bus. */ - if (_wait_for_response(dev, SAMD21_I2C_TIMEOUT) < 0) { + if (_wait_for_response(dev, SAM0_I2C_TIMEOUT) < 0) { return -ETIMEDOUT; } @@ -446,8 +409,9 @@ static inline int _read(SercomI2cm *dev, uint8_t *data, size_t length, /* Wait for response on bus. */ if (length > 0) { - if (_wait_for_response(dev, SAMD21_I2C_TIMEOUT) < 0) + if (_wait_for_response(dev, SAM0_I2C_TIMEOUT) < 0) { return -ETIMEDOUT; + } } count++; } diff --git a/cpu/sam0_common/periph/include/sercom_internal.h b/cpu/sam0_common/periph/include/sercom_internal.h new file mode 100644 index 000000000000..ce10634706c8 --- /dev/null +++ b/cpu/sam0_common/periph/include/sercom_internal.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2024 ML!PA Consulting GmbH + * + * 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 cpu_sam0_common + * @ingroup drivers_periph + * @defgroup drivers_periph_sercom Low-level SERCOM driver implementation + * @{ + * + * @file + * @brief Low-level SERCOM driver implementation + * + * @author Marian Buschsieweke + */ + +#ifndef SERCOM_INTERNAL_H +#define SERCOM_INTERNAL_H + +#include "cpu.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if DOXYGEN +# define SERCOM_NUMOF NUM /**< Number of SERCOM instances */ +#else +# if defined(SERCOM7) +# define SERCOM_NUMOF 8 +# elif defined(SERCOM6) +# define SERCOM_NUMOF 7 +# elif defined(SERCOM5) +# define SERCOM_NUMOF 6 +# elif defined(SERCOM4) +# define SERCOM_NUMOF 5 +# elif defined(SERCOM3) +# define SERCOM_NUMOF 4 +# elif defined(SERCOM2) +# define SERCOM_NUMOF 3 +# elif defined(SERCOM1) +# define SERCOM_NUMOF 2 +# elif defined(SERCOM0) +# define SERCOM_NUMOF 1 +# else +# error "No SERCOMs present according to vendor header files" +# endif +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* SERCOM_INTERNAL_H */ +/** @} */ diff --git a/cpu/sam0_common/periph/sercom.c b/cpu/sam0_common/periph/sercom.c new file mode 100644 index 000000000000..53e7833ab512 --- /dev/null +++ b/cpu/sam0_common/periph/sercom.c @@ -0,0 +1,340 @@ +/* + * Copyright (C) 2024 ML!PA Consulting GmbH + * + * 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 drivers_periph_sercom + * @{ + * + * @file + * @brief Low-level SERCOM driver implementation + * + * @author Marian Buschsieweke + * + * @} + */ + +#include "bitfield.h" +#include "compiler_hints.h" +#include "cpu.h" +#include "modules.h" +#include "mutex.h" +#include "periph_cpu.h" + +#if MODULE_PM_LAYERED && defined(SAM0_SERCOM_PM_BLOCK) +# include "pm_layered.h" +#endif + +#include "include/sercom_internal.h" + +#define ENABLE_DEBUG 0 +#include "debug.h" + +#if defined (CPU_COMMON_SAML1X) || defined (CPU_COMMON_SAMD5X) +# define SERCOM_HAS_DEDICATED_TX_ISR 1 +#endif + +static mutex_t _locks[SERCOM_NUMOF]; +static sercom_irq_cb_t _cbs[SERCOM_NUMOF]; +static void *_args[SERCOM_NUMOF]; + +static BITFIELD(_sercoms_acquired, SERCOM_NUMOF); + +__attribute__((const)) +Sercom *sercom_get_baseaddr(sercom_t sercom) +{ + assume((unsigned)sercom < SERCOM_NUMOF); + static Sercom * const addrs[] = { +#if SERCOM_NUMOF > 0 + SERCOM0, +#endif +#if SERCOM_NUMOF > 1 + SERCOM1, +#endif +#if SERCOM_NUMOF > 2 + SERCOM2, +#endif +#if SERCOM_NUMOF > 3 + SERCOM3, +#endif +#if SERCOM_NUMOF > 4 + SERCOM4, +#endif +#if SERCOM_NUMOF > 5 + SERCOM5, +#endif +#if SERCOM_NUMOF > 6 + SERCOM6, +#endif +#if SERCOM_NUMOF > 7 + SERCOM7, +#endif + }; + + return addrs[sercom]; +} + +/** + * @brief Enable peripheral clock for given SERCOM device + * + * @param[in] sercom SERCOM device + * @param[in] gclk Generator clock + */ +static void _sercom_clk_enable(sercom_t sercom, uint8_t gclk) +{ + sercom_apb_enable(sercom); + + sam0_gclk_enable(gclk); + sercom_gclk_enable(sercom, gclk); +} + +/** + * @brief Disable peripheral clock for given SERCOM device + * + * @param[in] sercom SERCOM device + */ +static void _sercom_clk_disable(sercom_t sercom) +{ + sercom_apb_disable(sercom); +} + +/** + * @brief Wait for a previous reset to be completed + */ +static void _wait_for_reset_to_complete(Sercom *dev) +{ +#ifdef SERCOM_SPI_STATUS_SYNCBUSY + while (dev->SPI.STATUS.reg & SERCOM_SPI_STATUS_SYNCBUSY) {} +#else + while (dev->SPI.SYNCBUSY.reg) {} +#endif + + while (dev->SPI.CTRLA.reg & SERCOM_SPI_CTRLA_SWRST) {} +} + +void sercom_acquire(sercom_t sercom, uint8_t gclk, + sercom_irq_cb_t irq_cb, void *irq_arg) +{ + assume((unsigned)sercom < SERCOM_NUMOF); + mutex_lock(&_locks[sercom]); + Sercom *dev = sercom_get_baseaddr(sercom); + DEBUG("[sercom] acquiring SERCOM%d @ %p\n", (unsigned)sercom, (void *)dev); + + /* track state to detect possible double frees */ + if (IS_ACTIVE(DEVELHELP)) { + bf_set_atomic(_sercoms_acquired, sercom); + } + + _cbs[sercom] = irq_cb; + _args[sercom] = irq_arg; + + _sercom_clk_enable(sercom, gclk); + + /* A potential previous call to sercom_release() did not wait for the reset + * to be complete to not waste time. But we need to do so now, in case it + * is not yet finished anyway */ + _wait_for_reset_to_complete(dev); + + /* SERCOM should now be reset: Either, because this is the first + * time we acquire it or because sercom_release() did a reset of the + * SERCOM */ + assume(!dev->SPI.CTRLA.reg); + + if (irq_cb) { +#if SERCOM_HAS_DEDICATED_TX_ISR + NVIC_EnableIRQ(SERCOM0_2_IRQn + (sercom * 4)); + NVIC_EnableIRQ(SERCOM0_0_IRQn + (sercom * 4)); +#else + NVIC_EnableIRQ(SERCOM0_IRQn + sercom); +#endif + } + +#if MODULE_PM_LAYERED && defined(SAM0_SERCOM_PM_BLOCK) + pm_block(SAM0_SERCOM_PM_BLOCK); +#endif +} + +void sercom_release(sercom_t sercom) +{ + assume((unsigned)sercom < SERCOM_NUMOF); + + Sercom *dev = sercom_get_baseaddr(sercom); + DEBUG("[sercom] releasing SERCOM%d @ %p\n", (unsigned)sercom, (void *)dev); + + /* detect possible double releases: */ + if (IS_ACTIVE(DEVELHELP)) { + assume(bf_isset(_sercoms_acquired, sercom)); + bf_unset_atomic(_sercoms_acquired, sercom); + } + +#if SERCOM_HAS_DEDICATED_TX_ISR + NVIC_DisableIRQ(SERCOM0_2_IRQn + (sercom * 4)); + NVIC_DisableIRQ(SERCOM0_0_IRQn + (sercom * 4)); +#else + NVIC_DisableIRQ(SERCOM0_IRQn + sercom); +#endif + + dev->SPI.CTRLA.reg = SERCOM_SPI_CTRLA_SWRST; + _sercom_clk_disable(sercom); + _cbs[sercom] = NULL; + _args[sercom] = NULL; + +#if IS_ACTIVE(MODULE_PM_LAYERED) && defined(SAM0_SERCOM_PM_BLOCK) + pm_unblock(SAM0_SERCOM_PM_BLOCK); +#endif + mutex_unlock(&_locks[sercom]); +} + +static void _irq_handler(sercom_t sercom) +{ + _cbs[sercom](_args[sercom]); + cortexm_isr_end(); +} + +#if SERCOM_NUMOF > 0 +# if SERCOM_HAS_DEDICATED_TX_ISR +void isr_sercom0_2(void) +{ + _irq_handler(0); +} +void isr_sercom0_0(void) +{ + _irq_handler(0); +} +# else +void isr_sercom0(void) +{ + _irq_handler(0); +} +# endif +#endif + +#if SERCOM_NUMOF > 1 +# if SERCOM_HAS_DEDICATED_TX_ISR +void isr_sercom1_2(void) +{ + _irq_handler(1); +} +void isr_sercom1_0(void) +{ + _irq_handler(1); +} +# else +void isr_sercom1(void) +{ + _irq_handler(1); +} +# endif +#endif + +#if SERCOM_NUMOF > 2 +# if SERCOM_HAS_DEDICATED_TX_ISR +void isr_sercom2_2(void) +{ + _irq_handler(2); +} +void isr_sercom2_0(void) +{ + _irq_handler(2); +} +# else +void isr_sercom2(void) +{ + _irq_handler(2); +} +# endif +#endif + +#if SERCOM_NUMOF > 3 +# if SERCOM_HAS_DEDICATED_TX_ISR +void isr_sercom3_2(void) +{ + _irq_handler(3); +} +void isr_sercom3_0(void) +{ + _irq_handler(3); +} +# else +void isr_sercom3(void) +{ + _irq_handler(3); +} +# endif +#endif + +#if SERCOM_NUMOF > 4 +# if SERCOM_HAS_DEDICATED_TX_ISR +void isr_sercom4_2(void) +{ + _irq_handler(4); +} +void isr_sercom4_0(void) +{ + _irq_handler(4); +} +# else +void isr_sercom4(void) +{ + _irq_handler(4); +} +# endif +#endif + +#if SERCOM_NUMOF > 5 +# if SERCOM_HAS_DEDICATED_TX_ISR +void isr_sercom5_2(void) +{ + _irq_handler(5); +} +void isr_sercom5_0(void) +{ + _irq_handler(5); +} +# else +void isr_sercom5(void) +{ + _irq_handler(5); +} +# endif +#endif + +#if SERCOM_NUMOF > 6 +# if SERCOM_HAS_DEDICATED_TX_ISR +void isr_sercom6_2(void) +{ + _irq_handler(6); +} +void isr_sercom6_0(void) +{ + _irq_handler(6); +} +# else +void isr_sercom6(void) +{ + _irq_handler(6); +} +# endif +#endif + +#if SERCOM_NUMOF > 7 +# if SERCOM_HAS_DEDICATED_TX_ISR +void isr_sercom7_2(void) +{ + _irq_handler(7); +} +void isr_sercom7_0(void) +{ + _irq_handler(7); +} +# else +void isr_sercom7(void) +{ + _irq_handler(7); +} +# endif +#endif diff --git a/cpu/sam0_common/periph/spi.c b/cpu/sam0_common/periph/spi.c index 2997acde51e2..4b2ae2831a01 100644 --- a/cpu/sam0_common/periph/spi.c +++ b/cpu/sam0_common/periph/spi.c @@ -33,11 +33,16 @@ #include "cpu.h" #include "mutex.h" #include "periph/spi.h" -#include "pm_layered.h" #define ENABLE_DEBUG 0 #include "debug.h" +#if MODULE_PERIPH_SPI_ON_QSPI +# define QSPI_NUMOF 1 +#else +# define QSPI_NUMOF 0 +#endif + /** * @brief Array holding one pre-initialized mutex for each SPI device */ @@ -55,12 +60,9 @@ static DmacDescriptor DMA_DESCRIPTOR_ATTRS tx_desc[SPI_NUMOF]; static DmacDescriptor DMA_DESCRIPTOR_ATTRS rx_desc[SPI_NUMOF]; #endif -/** - * @brief Shortcut for accessing the used SPI SERCOM device - */ -static inline SercomSpi *dev(spi_t bus) +static SercomSpi *_dev(spi_t bus) { - return (SercomSpi *)spi_config[bus].dev; + return spi_config[bus].dev; } static inline bool _is_qspi(spi_t bus) @@ -93,8 +95,6 @@ static inline void poweron(spi_t bus) { if (_is_qspi(bus)) { _qspi_clk_enable(); - } else { - sercom_clk_en(dev(bus)); } } @@ -102,34 +102,9 @@ static inline void poweroff(spi_t bus) { if (_is_qspi(bus)) { _qspi_clk_disable(); - } else { - sercom_clk_dis(dev(bus)); } } -static inline void _reset(SercomSpi *dev) -{ - dev->CTRLA.reg |= SERCOM_SPI_CTRLA_SWRST; - while (dev->CTRLA.reg & SERCOM_SPI_CTRLA_SWRST) {} - -#ifdef SERCOM_SPI_STATUS_SYNCBUSY - while (dev->STATUS.reg & SERCOM_SPI_STATUS_SYNCBUSY) {} -#else - while (dev->SYNCBUSY.reg & SERCOM_SPI_SYNCBUSY_SWRST) {} -#endif -} - -static inline void _disable(SercomSpi *dev) -{ - dev->CTRLA.reg = 0; - -#ifdef SERCOM_SPI_STATUS_SYNCBUSY - while (dev->STATUS.reg & SERCOM_SPI_STATUS_SYNCBUSY) {} -#else - while (dev->SYNCBUSY.reg) {} -#endif -} - static inline void _enable(SercomSpi *dev) { dev->CTRLA.reg |= SERCOM_SPI_CTRLA_ENABLE; @@ -251,17 +226,9 @@ void _qspi_blocking_transfer(const void *out, void *in, size_t len); * @brief SERCOM peripheral in SPI mode * @{ */ -static void _init_spi(spi_t bus, SercomSpi *dev) +static void _init_spi(spi_t bus) { - /* reset all device configuration */ - _reset(dev); - - /* configure base clock */ - sercom_set_gen(dev, spi_config[bus].gclk_src); - - /* enable receiver and configure character size to 8-bit - * no synchronization needed, as SERCOM device is not enabled */ - dev->CTRLB.reg = SERCOM_SPI_CTRLB_CHSIZE(0) | SERCOM_SPI_CTRLB_RXEN; + SercomSpi *dev = _dev(bus); /* set up DMA channels */ _init_dma(bus, &dev->DATA.reg, &dev->DATA.reg); @@ -269,6 +236,10 @@ static void _init_spi(spi_t bus, SercomSpi *dev) static void _spi_acquire(spi_t bus, spi_mode_t mode, spi_clk_t clk) { + sercom_t sercom = sercom_id(spi_config[bus].dev); + DEBUG("[spi] acquire bus %u on SERCOM %u\n", + (unsigned)bus, (unsigned)sercom); + /* clock can't be higher than source clock */ uint32_t gclk_src = sam0_gclk_freq(spi_config[bus].gclk_src); if (clk > gclk_src) { @@ -281,55 +252,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; /* configure device to be master and set mode and pads, * * NOTE: we could configure the pads already during spi_init, but for * efficiency reason we do that here, so we can do all in one single write * to the CTRLA register */ - const uint32_t ctrla = SERCOM_SPI_CTRLA_MODE(0x3) /* 0x3 -> master */ - | SERCOM_SPI_CTRLA_DOPO(spi_config[bus].mosi_pad) - | SERCOM_SPI_CTRLA_DIPO(spi_config[bus].miso_pad) - | (mode << SERCOM_SPI_CTRLA_CPHA_Pos); - - /* first configuration or reconfiguration after altered device usage */ - if (dev(bus)->BAUD.reg != baud || dev(bus)->CTRLA.reg != ctrla) { - /* disable the device */ - _disable(dev(bus)); - - dev(bus)->BAUD.reg = baud; - dev(bus)->CTRLA.reg = ctrla; - /* no synchronization needed here, the enable synchronization below - * acts as a write-synchronization for both registers */ - } + uint32_t ctrla = SERCOM_SPI_CTRLA_MODE(0x3) /* 0x3 -> master */ + | SERCOM_SPI_CTRLA_DOPO(spi_config[bus].mosi_pad) + | SERCOM_SPI_CTRLA_DIPO(spi_config[bus].miso_pad) + | (mode << SERCOM_SPI_CTRLA_CPHA_Pos); + uint32_t ctrlb = SERCOM_SPI_CTRLB_CHSIZE(0) | SERCOM_SPI_CTRLB_RXEN; - /* finally enable the device */ - _enable(dev(bus)); -} + sercom_acquire(sercom, spi_config[bus].gclk_src, NULL, NULL); -static inline void _spi_release(spi_t bus) -{ - /* disable the device */ - _disable(dev(bus)); + SercomSpi *dev = _dev(bus); + dev->CTRLA.reg = ctrla; + dev->CTRLB.reg = ctrlb; + dev->BAUD.reg = baud; + + /* finally enable the device */ + _enable(dev); } static void _spi_blocking_transfer(spi_t bus, const void *out, void *in, size_t len) { const uint8_t *out_buf = out; uint8_t *in_buf = in; + SercomSpi *dev = _dev(bus); for (size_t i = 0; i < len; i++) { uint8_t tmp = (out_buf) ? out_buf[i] : 0; /* transmit byte on MOSI */ - dev(bus)->DATA.reg = tmp; + dev->DATA.reg = tmp; /* wait until byte has been sampled on MISO */ - while (!(dev(bus)->INTFLAG.reg & SERCOM_SPI_INTFLAG_RXC)) {} + while (!(dev->INTFLAG.reg & SERCOM_SPI_INTFLAG_RXC)) {} /* consume the byte */ - tmp = dev(bus)->DATA.reg; + tmp = dev->DATA.reg; if (in_buf) { in_buf[i] = tmp; @@ -355,29 +318,56 @@ void spi_init(spi_t bus) if (_is_qspi(bus)) { _init_qspi(bus); } else { - _init_spi(bus, dev(bus)); + _init_spi(bus); } /* put device back to sleep */ poweroff(bus); } +static void _attach_pins(spi_t bus) +{ + if (gpio_is_valid(spi_config[bus].mosi_pin)) { + gpio_init_mux(spi_config[bus].mosi_pin, spi_config[bus].mosi_mux); + } + + if (gpio_is_valid(spi_config[bus].miso_pin)) { + gpio_init_mux(spi_config[bus].miso_pin, spi_config[bus].miso_mux); + } + + if (gpio_is_valid(spi_config[bus].clk_pin)) { + gpio_init_mux(spi_config[bus].clk_pin, spi_config[bus].clk_mux); + } +} + +static void _detach_pins(spi_t bus) +{ + if (gpio_is_valid(spi_config[bus].mosi_pin)) { + gpio_disable_mux(spi_config[bus].mosi_pin); + } + + if (gpio_is_valid(spi_config[bus].miso_pin)) { + gpio_disable_mux(spi_config[bus].miso_pin); + } + + if (gpio_is_valid(spi_config[bus].clk_pin)) { + gpio_disable_mux(spi_config[bus].clk_pin); + } +} + int spi_init_with_gpio_mode(spi_t bus, const spi_gpio_mode_t* mode) { assert(bus < SPI_NUMOF); if (gpio_is_valid(spi_config[bus].mosi_pin)) { gpio_init(spi_config[bus].miso_pin, mode->mosi); - gpio_init_mux(spi_config[bus].miso_pin, spi_config[bus].miso_mux); } if (gpio_is_valid(spi_config[bus].miso_pin)) { gpio_init(spi_config[bus].mosi_pin, mode->miso); - gpio_init_mux(spi_config[bus].mosi_pin, spi_config[bus].mosi_mux); } if (gpio_is_valid(spi_config[bus].clk_pin)) { - /* clk_pin will be muxed during acquire / release */ gpio_init(spi_config[bus].clk_pin, mode->sclk); } mutex_unlock(&locks[bus]); @@ -398,12 +388,11 @@ void spi_init_pins(spi_t bus) void spi_deinit_pins(spi_t bus) { + /* pins are detached by default, so that other users of the SERCOM can + * route pins to the SERCOM. We just need to make sure calls to + * `spi_acquire()` will block until pins are returned to the SPI bus, which + * we use the mutex for. */ mutex_lock(&locks[bus]); - - if (gpio_is_valid(spi_config[bus].miso_pin)) { - gpio_disable_mux(spi_config[bus].miso_pin); - } - gpio_disable_mux(spi_config[bus].mosi_pin); } void spi_acquire(spi_t bus, spi_cs_t cs, spi_mode_t mode, spi_clk_t clk) @@ -411,7 +400,10 @@ void spi_acquire(spi_t bus, spi_cs_t cs, spi_mode_t mode, spi_clk_t clk) (void)cs; assert((unsigned)bus < SPI_NUMOF); - /* get exclusive access to the device */ + /* Get exclusive access to the SPI pins. (Exclusive access to the SERCOM + * is internally already managed, but spi_deinit_pins() will get GPIO + * access to the SPI pins exclusively.) + */ mutex_lock(&locks[bus]); /* power on the device */ @@ -419,28 +411,30 @@ void spi_acquire(spi_t bus, spi_cs_t cs, spi_mode_t mode, spi_clk_t clk) if (_is_qspi(bus)) { _qspi_acquire(mode, clk); - } else { + } + else { _spi_acquire(bus, mode, clk); + _attach_pins(bus); } - /* mux clk_pin to SPI peripheral */ - gpio_init_mux(spi_config[bus].clk_pin, spi_config[bus].clk_mux); } void spi_release(spi_t bus) { - /* Demux clk_pin back to GPIO_OUT function. Otherwise it will get HIGH-Z - * and lead to unexpected current draw by SPI salves. */ - gpio_disable_mux(spi_config[bus].clk_pin); - if (_is_qspi(bus)) { + DEBUG("[spi] release bus %u on QSPI\n", (unsigned)bus); _qspi_release(); - } else { - _spi_release(bus); - } - /* power off the device */ - poweroff(bus); + /* power off the device */ + poweroff(bus); + } + else { + sercom_t sercom = sercom_id(spi_config[bus].dev); + DEBUG("[spi] release bus %u on SERCOM %u\n", + (unsigned)bus, (unsigned)sercom); + _detach_pins(bus); + sercom_release(sercom); + } /* release access to the device */ mutex_unlock(&locks[bus]); @@ -450,7 +444,8 @@ static void _blocking_transfer(spi_t bus, const void *out, void *in, size_t len) { if (_is_qspi(bus)) { _qspi_blocking_transfer(out, in, len); - } else { + } + else { _spi_blocking_transfer(bus, out, in, len); } } @@ -503,6 +498,9 @@ static void _dma_transfer_regs(spi_t bus, uint8_t reg, const uint8_t *out, void spi_transfer_regs(spi_t bus, spi_cs_t cs, uint8_t reg, const void *out, void *in, size_t len) { + DEBUG("[spi] bus %u: transferring %u regs at %x\n", + (unsigned)bus, (unsigned)len, (unsigned)reg); + if (cs != SPI_CS_UNDEF) { gpio_clear((gpio_t)cs); } @@ -533,6 +531,8 @@ uint8_t spi_transfer_reg(spi_t bus, spi_cs_t cs, uint8_t reg, uint8_t out) void spi_transfer_bytes(spi_t bus, spi_cs_t cs, bool cont, const void *out, void *in, size_t len) { + DEBUG("[spi] bus %u: transferring %u B\n", + (unsigned)bus, (unsigned)len); assert(out || in); if (cs != SPI_CS_UNDEF) { diff --git a/cpu/sam0_common/periph/uart.c b/cpu/sam0_common/periph/uart.c index 6930d79598e3..5468cd2f6a26 100644 --- a/cpu/sam0_common/periph/uart.c +++ b/cpu/sam0_common/periph/uart.c @@ -26,11 +26,11 @@ * @} */ -#include "cpu.h" -#include "pm_layered.h" - -#include "periph/uart.h" +#include "bitfield.h" +#include "modules.h" #include "periph/gpio.h" +#include "periph/uart.h" +#include "periph_cpu.h" #define ENABLE_DEBUG 0 #include "debug.h" @@ -64,20 +64,56 @@ static tsrb_t uart_tx_rb[UART_NUMOF]; static uint8_t uart_tx_rb_buf[UART_NUMOF][UART_TXBUF_SIZE]; #endif static uart_isr_ctx_t uart_ctx[UART_NUMOF]; +static uint32_t symbol_rates[UART_NUMOF]; +static BITFIELD(_enabled, UART_NUMOF) = { 0 }; + +static void uart_isr(void *arg); + +static bool _is_txondemand(uart_t uart) +{ + if (!IS_USED(MODULE_PERIPH_UART_TX_ONDEMAND)) { + return false; + } + + return uart_config[uart].flags & UART_FLAG_TX_ONDEMAND; +} + +gpio_t uart_pin_cts(uart_t uart) +{ +#ifdef MODULE_PERIPH_UART_HW_FC + if (uart_config[uart].tx_pad == UART_PAD_TX_0_RTS_2_CTS_3) { + return uart_config[uart].cts_pin; + } +#endif + (void)uart; + return GPIO_UNDEF; +} + +gpio_t uart_pin_rts(uart_t uart) +{ +#ifdef MODULE_PERIPH_UART_HW_FC + if (uart_config[uart].tx_pad == UART_PAD_TX_0_RTS_2_CTS_3) { + return uart_config[uart].rts_pin; + } +#endif + (void)uart; + return GPIO_UNDEF; +} /** - * @brief Get the pointer to the base register of the given UART device + * @brief Get the pointer to the base register of the given UART * - * @param[in] dev UART device identifier + * @param[in] uart UART interface number * * @return base register address */ -static inline SercomUsart *dev(uart_t dev) +static SercomUsart *_dev(uart_t uart) { - return uart_config[dev].dev; + return uart_config[uart].dev; } -static inline void _syncbusy(SercomUsart *dev) +MAYBE_UNUSED +static void _syncbusy(SercomUsart *dev) { #ifdef SERCOM_USART_SYNCBUSY_MASK while (dev->SYNCBUSY.reg) {} @@ -86,19 +122,7 @@ static inline void _syncbusy(SercomUsart *dev) #endif } -static inline void _reset(SercomUsart *dev) -{ - dev->CTRLA.reg = SERCOM_USART_CTRLA_SWRST; - while (dev->CTRLA.reg & SERCOM_SPI_CTRLA_SWRST) {} - -#ifdef SERCOM_USART_SYNCBUSY_MASK - while (dev->SYNCBUSY.reg & SERCOM_USART_SYNCBUSY_SWRST) {} -#else - while (dev->STATUS.reg & SERCOM_USART_STATUS_SYNCBUSY) {} -#endif -} - -static void _set_baud(uart_t uart, uint32_t baudrate, uint32_t f_src) +static uint16_t _calculate_baud(uint32_t baudrate, uint32_t f_src) { #if IS_ACTIVE(CONFIG_SAM0_UART_BAUD_FRAC) /* Asynchronous Fractional */ @@ -106,8 +130,11 @@ static void _set_baud(uart_t uart, uint32_t baudrate, uint32_t f_src) /* BAUD * 8 + FP = (8 * f_src) / (S * f_baud) */ /* S * (BAUD + 8 * FP) = (8 * f_src) / f_baud */ uint32_t baud = (f_src * 8) / baudrate; - dev(uart)->BAUD.FRAC.FP = (baud >> 4) & 0x7; /* baud / 16 */ - dev(uart)->BAUD.FRAC.BAUD = baud >> 7; /* baud / (8 * 16) */ + SERCOM_USART_BAUD_Type baudreg = { .FRAC = { + .FP = (baud >> 4) & 0x7, /* baud / 16 */ + .BAUD = baud >> 7, /* baud / (8 * 16) */ + } }; + return baudreg.reg; #else /* Asynchronous Arithmetic */ /* BAUD = 2^16 * (2^0 - 2^4 * f_baud / f_src) */ @@ -125,82 +152,106 @@ static void _set_baud(uart_t uart, uint32_t baudrate, uint32_t f_src) uint32_t rem = baudrate % f_src; uint8_t scale = 20 - pow; - dev(uart)->BAUD.reg = (tmp << scale) - (rem << scale) / f_src; + return (tmp << scale) - (rem << scale) / f_src; #endif } +static void _attach_pins(uart_t uart) +{ + if (gpio_is_valid(uart_config[uart].rx_pin)) { + gpio_init_mux(uart_config[uart].rx_pin, uart_config[uart].mux); + } + + if (gpio_is_valid(uart_config[uart].tx_pin) && + !_is_txondemand(uart)) { + gpio_init_mux(uart_config[uart].tx_pin, uart_config[uart].mux); + } + + /* If RTS/CTS needed, enable them */ + /* Ensure RTS is defined */ + if (gpio_is_valid(uart_pin_rts(uart))) { + gpio_init_mux(uart_pin_rts(uart), uart_config[uart].mux); + } + /* Ensure CTS is defined */ + if (gpio_is_valid(uart_pin_cts(uart))) { + gpio_init_mux(uart_pin_cts(uart), uart_config[uart].mux); + } +} + +static void _detach_pins(uart_t uart) +{ + if (gpio_is_valid(uart_config[uart].rx_pin)) { + gpio_disable_mux(uart_config[uart].rx_pin); + } + + if (gpio_is_valid(uart_config[uart].tx_pin) + && !_is_txondemand(uart)) { + gpio_disable_mux(uart_config[uart].tx_pin); + } + + /* If RTS/CTS needed, enable them */ + /* Ensure RTS is defined */ + if (gpio_is_valid(uart_pin_rts(uart))) { + gpio_disable_mux(uart_pin_rts(uart)); + } + /* Ensure CTS is defined */ + if (gpio_is_valid(uart_pin_cts(uart))) { + gpio_disable_mux(uart_pin_cts(uart)); + } +} + void uart_enable_tx(uart_t uart) { - /* configure RX pin */ - if (uart_config[uart].tx_pin != GPIO_UNDEF) { + if (gpio_is_valid(uart_config[uart].tx_pin)) { gpio_init_mux(uart_config[uart].tx_pin, uart_config[uart].mux); } } void uart_disable_tx(uart_t uart) { - /* configure RX pin */ - if (uart_config[uart].tx_pin != GPIO_UNDEF) { - gpio_init_mux(uart_config[uart].tx_pin, GPIO_MUX_A); + if (gpio_is_valid(uart_config[uart].tx_pin)) { + gpio_disable_mux(uart_config[uart].tx_pin); } } static void _configure_pins(uart_t uart) { /* configure RX pin */ - if (uart_config[uart].rx_pin != GPIO_UNDEF) { + if (gpio_is_valid(uart_config[uart].rx_pin)) { gpio_init(uart_config[uart].rx_pin, GPIO_IN); - gpio_init_mux(uart_config[uart].rx_pin, uart_config[uart].mux); } /* configure TX pin */ - if (uart_config[uart].tx_pin != GPIO_UNDEF && - !(uart_config[uart].flags & UART_FLAG_TX_ONDEMAND)) { + if (gpio_is_valid(uart_config[uart].tx_pin)) { gpio_set(uart_config[uart].tx_pin); gpio_init(uart_config[uart].tx_pin, GPIO_OUT); - gpio_init_mux(uart_config[uart].tx_pin, uart_config[uart].mux); } -#ifdef MODULE_PERIPH_UART_HW_FC /* If RTS/CTS needed, enable them */ - if (uart_config[uart].tx_pad == UART_PAD_TX_0_RTS_2_CTS_3) { - /* Ensure RTS is defined */ - if (uart_config[uart].rts_pin != GPIO_UNDEF) { - gpio_init_mux(uart_config[uart].rts_pin, uart_config[uart].mux); - } - /* Ensure CTS is defined */ - if (uart_config[uart].cts_pin != GPIO_UNDEF) { - gpio_init_mux(uart_config[uart].cts_pin, uart_config[uart].mux); - } + /* Ensure RTS is defined */ + if (gpio_is_valid(uart_pin_rts(uart))) { + gpio_init(uart_pin_rts(uart), GPIO_OUT); + } + /* Ensure CTS is defined */ + if (gpio_is_valid(uart_pin_cts(uart))) { + gpio_init(uart_pin_cts(uart), GPIO_IN); } -#endif } -int uart_init(uart_t uart, uint32_t baudrate, uart_rx_cb_t rx_cb, void *arg) +int uart_init(uart_t uart, uint32_t baud, uart_rx_cb_t rx_cb, void *arg) { - if (uart >= UART_NUMOF) { - return UART_NODEV; + DEBUG("[uart] init %u\n", (unsigned)uart); + /* if UART is still on, we disable it first */ + if (bf_isset(_enabled, uart)) { + uart_poweroff(uart); } - /* enable peripheral clock */ - sercom_clk_en(dev(uart)); - -#if IS_ACTIVE(MODULE_PM_LAYERED) && defined(SAM0_UART_PM_BLOCK) - /* clear previously blocked power modes */ - if (dev(uart)->CTRLA.reg & SERCOM_USART_CTRLA_ENABLE) { - /* RX IRQ is enabled */ - if (dev(uart)->INTENSET.reg & SERCOM_USART_INTENSET_RXC) { - pm_unblock(SAM0_UART_PM_BLOCK); - } - /* data reg empty IRQ is enabled -> sending data was in progress */ - if (dev(uart)->INTENSET.reg & SERCOM_USART_INTENSET_DRE) { - pm_unblock(SAM0_UART_PM_BLOCK); - } + if (uart >= UART_NUMOF) { + return UART_NODEV; } -#endif - /* must disable here first to ensure idempotency */ - dev(uart)->CTRLA.reg = 0; + symbol_rates[uart] = baud; + uart_ctx[uart] = (uart_isr_ctx_t){ .rx_cb = rx_cb, .arg = arg }; #ifdef MODULE_PERIPH_UART_NONBLOCKING /* set up the TX buffer */ @@ -210,91 +261,7 @@ int uart_init(uart_t uart, uint32_t baudrate, uart_rx_cb_t rx_cb, void *arg) /* configure pins */ _configure_pins(uart); - /* reset the UART device */ - _reset(dev(uart)); - - /* configure clock generator */ - sercom_set_gen(dev(uart), uart_config[uart].gclk_src); - - uint32_t f_src = sam0_gclk_freq(uart_config[uart].gclk_src); - -#if IS_ACTIVE(CONFIG_SAM0_UART_BAUD_FRAC) - uint32_t sampr; - /* constraint: f_baud ≤ f_src / S */ - if (baudrate * 16 > f_src) { - /* 8x oversampling */ - sampr = SERCOM_USART_CTRLA_SAMPR(0x3); - f_src <<= 1; - } else { - /* 16x oversampling */ - sampr = SERCOM_USART_CTRLA_SAMPR(0x1); - } -#endif - - /* set asynchronous mode w/o parity, LSB first, TX and RX pad as specified - * by the board in the periph_conf.h, x16 sampling and use internal clock */ - dev(uart)->CTRLA.reg = SERCOM_USART_CTRLA_DORD -#if IS_ACTIVE(CONFIG_SAM0_UART_BAUD_FRAC) - /* enable Asynchronous Fractional mode */ - | sampr -#endif - | SERCOM_USART_CTRLA_TXPO(uart_config[uart].tx_pad) - | SERCOM_USART_CTRLA_RXPO(uart_config[uart].rx_pad) - | SERCOM_USART_CTRLA_MODE(0x1); - - /* Set run in standby mode if enabled */ - if (uart_config[uart].flags & UART_FLAG_RUN_STANDBY) { - dev(uart)->CTRLA.reg |= SERCOM_USART_CTRLA_RUNSTDBY; - } - - /* calculate and set baudrate */ - _set_baud(uart, baudrate, f_src); - - /* enable transmitter, and configure 8N1 mode */ - if (uart_config[uart].tx_pin != GPIO_UNDEF) { - dev(uart)->CTRLB.reg = SERCOM_USART_CTRLB_TXEN; - } else { - dev(uart)->CTRLB.reg = 0; - } - - /* enable receiver and RX interrupt if configured */ - if ((rx_cb) && (uart_config[uart].rx_pin != GPIO_UNDEF)) { - uart_ctx[uart].rx_cb = rx_cb; - uart_ctx[uart].arg = arg; -#ifdef UART_HAS_TX_ISR - /* enable RXNE ISR */ - NVIC_EnableIRQ(SERCOM0_2_IRQn + (sercom_id(dev(uart)) * 4)); -#else - /* enable UART ISR */ - NVIC_EnableIRQ(SERCOM0_IRQn + sercom_id(dev(uart))); -#endif /* UART_HAS_TX_ISR */ - dev(uart)->CTRLB.reg |= SERCOM_USART_CTRLB_RXEN; - dev(uart)->INTENSET.reg = SERCOM_USART_INTENSET_RXC; -#if IS_ACTIVE(MODULE_PM_LAYERED) && defined(SAM0_UART_PM_BLOCK) - /* block power mode for rx IRQs */ - pm_block(SAM0_UART_PM_BLOCK); -#endif - /* set wakeup receive from sleep if enabled */ - if (uart_config[uart].flags & UART_FLAG_WAKEUP) { - dev(uart)->CTRLB.reg |= SERCOM_USART_CTRLB_SFDE; - } - } -#ifdef MODULE_PERIPH_UART_NONBLOCKING -#ifndef UART_HAS_TX_ISR - else { - /* enable UART ISR */ - NVIC_EnableIRQ(SERCOM0_IRQn + sercom_id(dev(uart))); - } -#else - /* enable TXE ISR */ - NVIC_EnableIRQ(SERCOM0_0_IRQn + (sercom_id(dev(uart)) * 4)); -#endif -#endif /* MODULE_PERIPH_UART_NONBLOCKING */ - - _syncbusy(dev(uart)); - - /* and finally enable the device */ - dev(uart)->CTRLA.reg |= SERCOM_USART_CTRLA_ENABLE; + uart_poweron(uart); return UART_OK; } @@ -320,50 +287,24 @@ void uart_deinit_pins(uart_t uart) gpio_disable_mux(uart_config[uart].tx_pin); } -#ifdef MODULE_PERIPH_UART_HW_FC /* If RTS/CTS needed, enable them */ - if (uart_config[uart].tx_pad == UART_PAD_TX_0_RTS_2_CTS_3) { - /* Ensure RTS is defined */ - if (uart_config[uart].rts_pin != GPIO_UNDEF) { - gpio_disable_mux(uart_config[uart].rts_pin); - } - /* Ensure CTS is defined */ - if (uart_config[uart].cts_pin != GPIO_UNDEF) { - gpio_disable_mux(uart_config[uart].cts_pin); - } + /* Ensure RTS is defined */ + if (gpio_is_valid(uart_pin_rts(uart))) { + gpio_disable_mux(uart_pin_rts(uart)); } -#endif -} - -gpio_t uart_pin_cts(uart_t uart) -{ -#ifdef MODULE_PERIPH_UART_HW_FC - if (uart_config[uart].tx_pad == UART_PAD_TX_0_RTS_2_CTS_3) { - return uart_config[uart].cts_pin; + /* Ensure CTS is defined */ + if (gpio_is_valid(uart_pin_cts(uart))) { + gpio_disable_mux(uart_pin_cts(uart)); } -#endif - (void)uart; - return GPIO_UNDEF; -} - -gpio_t uart_pin_rts(uart_t uart) -{ -#ifdef MODULE_PERIPH_UART_HW_FC - if (uart_config[uart].tx_pad == UART_PAD_TX_0_RTS_2_CTS_3) { - return uart_config[uart].rts_pin; - } -#endif - (void)uart; - return GPIO_UNDEF; } void uart_write(uart_t uart, const uint8_t *data, size_t len) { - if (uart_config[uart].tx_pin == GPIO_UNDEF) { + if (!gpio_is_valid(uart_config[uart].tx_pin)) { return; } - if (!(dev(uart)->CTRLA.reg & SERCOM_USART_CTRLA_ENABLE)) { + if (!(_dev(uart)->CTRLA.reg & SERCOM_USART_CTRLA_ENABLE)) { return; } @@ -372,8 +313,8 @@ void uart_write(uart_t uart, const uint8_t *data, size_t len) if (irq_is_in() || __get_PRIMASK()) { /* if ring buffer is full free up a spot */ if (tsrb_full(&uart_tx_rb[uart])) { - while (!(dev(uart)->INTFLAG.reg & SERCOM_USART_INTFLAG_DRE)) {} - dev(uart)->DATA.reg = tsrb_get_one(&uart_tx_rb[uart]); + while (!(_dev(uart)->INTFLAG.reg & SERCOM_USART_INTFLAG_DRE)) {} + _dev(uart)->DATA.reg = tsrb_get_one(&uart_tx_rb[uart]); } tsrb_add_one(&uart_tx_rb[uart], *data); } @@ -386,70 +327,125 @@ void uart_write(uart_t uart, const uint8_t *data, size_t len) /* tsrb_add_one() is blocking the thread. It may happen that * the corresponding ISR has turned off DRE IRQs and, thus, * unblocked the corresponding power mode. */ - if (!(dev(uart)->INTENSET.reg & SERCOM_USART_INTENSET_DRE)) { + if (!(_dev(uart)->INTENSET.reg & SERCOM_USART_INTENSET_DRE)) { pm_block(SAM0_UART_PM_BLOCK); } - dev(uart)->INTENSET.reg = SERCOM_USART_INTENSET_DRE; + _dev(uart)->INTENSET.reg = SERCOM_USART_INTENSET_DRE; irq_restore(state); #else - dev(uart)->INTENSET.reg = SERCOM_USART_INTENSET_DRE; + _dev(uart)->INTENSET.reg = SERCOM_USART_INTENSET_DRE; #endif } #else for (const void* end = data + len; data != end; ++data) { - while (!(dev(uart)->INTFLAG.reg & SERCOM_USART_INTFLAG_DRE)) {} - dev(uart)->DATA.reg = *data; + while (!(_dev(uart)->INTFLAG.reg & SERCOM_USART_INTFLAG_DRE)) {} + _dev(uart)->DATA.reg = *data; } - while (!(dev(uart)->INTFLAG.reg & SERCOM_USART_INTFLAG_TXC)) {} + while (!(_dev(uart)->INTFLAG.reg & SERCOM_USART_INTFLAG_TXC)) {} #endif } void uart_poweron(uart_t uart) { - sercom_clk_en(dev(uart)); + sercom_t sercom = sercom_id(uart_config[uart].dev); + DEBUG("[uart] powering on #%u on SERCOM%u\n", (unsigned)uart, (unsigned)sercom); + if (bf_isset(_enabled, uart)) { + /* already on, nothing to do */ + return; + } - /* the enable bit must be read and written atomically */ - unsigned state = irq_disable(); -#if IS_ACTIVE(MODULE_PM_LAYERED) && defined(SAM0_UART_PM_BLOCK) - /* block required power modes */ - if (!(dev(uart)->CTRLA.reg & SERCOM_USART_CTRLA_ENABLE)) { - /* RX IRQ is enabled */ - if (dev(uart)->INTENSET.reg & SERCOM_USART_INTENSET_RXC) { - pm_block(SAM0_UART_PM_BLOCK); - } - /* data reg empty IRQ is enabled -> sending data was in progress */ - if (dev(uart)->INTENSET.reg & SERCOM_USART_INTENSET_DRE) { - pm_block(SAM0_UART_PM_BLOCK); - } + bf_set_atomic(_enabled, uart); + + uint32_t f_src = sam0_gclk_freq(uart_config[uart].gclk_src); + +#if IS_ACTIVE(CONFIG_SAM0_UART_BAUD_FRAC) + uint32_t sampr; + /* constraint: f_baud ≤ f_src / S */ + if (symbol_rates[uart] * 16 > f_src) { + /* 8x oversampling */ + sampr = SERCOM_USART_CTRLA_SAMPR(0x3); + f_src <<= 1; + } + else { + /* 16x oversampling */ + sampr = SERCOM_USART_CTRLA_SAMPR(0x1); } #endif - dev(uart)->CTRLA.reg |= SERCOM_USART_CTRLA_ENABLE; - irq_restore(state); - _syncbusy(dev(uart)); + /* set asynchronous mode w/o parity, LSB first, TX and RX pad as specified + * by the board in the periph_conf.h, x16 sampling and use internal clock */ + uint32_t ctrla = SERCOM_USART_CTRLA_DORD +#if IS_ACTIVE(CONFIG_SAM0_UART_BAUD_FRAC) + /* enable Asynchronous Fractional mode */ + | sampr +#endif + | SERCOM_USART_CTRLA_TXPO(uart_config[uart].tx_pad) + | SERCOM_USART_CTRLA_RXPO(uart_config[uart].rx_pad) + | SERCOM_USART_CTRLA_MODE(0x1); + + /* Set run in standby mode if enabled */ + if (uart_config[uart].flags & UART_FLAG_RUN_STANDBY) { + ctrla |= SERCOM_USART_CTRLA_RUNSTDBY; + } + + /* calculate symbol rate */ + uint16_t baud = _calculate_baud(symbol_rates[uart], f_src); + + uint32_t ctrlb = 0; + /* enable transmitter, and configure 8N1 mode */ + if (gpio_is_valid(uart_config[uart].tx_pin)) { + ctrlb = SERCOM_USART_CTRLB_TXEN; + } + + sercom_irq_cb_t irq_cb = NULL; + + /* enable receiver and RX interrupt if configured */ + if ((uart_ctx[uart].rx_cb) && (gpio_is_valid(uart_config[uart].rx_pin))) { + irq_cb = uart_isr; + ctrlb |= SERCOM_USART_CTRLB_RXEN; + + /* set wakeup receive from sleep if enabled */ + if (uart_config[uart].flags & UART_FLAG_WAKEUP) { + ctrlb |= SERCOM_USART_CTRLB_SFDE; + } + } + + if (IS_USED(MODULE_PERIPH_UART_NONBLOCKING)) { + irq_cb = uart_isr; + } + + sercom_acquire(sercom, uart_config[uart].gclk_src, irq_cb, (void *)(uintptr_t)uart); + + _attach_pins(uart); + + SercomUsart *dev = _dev(uart); + dev->CTRLA.reg = ctrla; + dev->CTRLB.reg = ctrlb; + dev->BAUD.reg = baud; + /* enable RX IRQ, if needed */ + if ((uart_ctx[uart].rx_cb) && (gpio_is_valid(uart_config[uart].rx_pin))) { + dev->INTENSET.reg = SERCOM_USART_INTENSET_RXC; + } + + /* and finally enable the device and the IRQs as needed */ + dev->CTRLA.reg |= SERCOM_USART_CTRLA_ENABLE; + _syncbusy(dev); } void uart_poweroff(uart_t uart) { - /* the enable bit must be read and written atomically */ - unsigned state = irq_disable(); -#if IS_ACTIVE(MODULE_PM_LAYERED) && defined(SAM0_UART_PM_BLOCK) - /* clear blocked power modes */ - if (dev(uart)->CTRLA.reg & SERCOM_USART_CTRLA_ENABLE) { - /* RX IRQ is enabled */ - if (dev(uart)->INTENSET.reg & SERCOM_USART_INTENSET_RXC) { - pm_unblock(SAM0_UART_PM_BLOCK); - } - /* data reg empty IRQ is enabled -> sending data is in progress */ - if (dev(uart)->INTENSET.reg & SERCOM_USART_INTENSET_DRE) { - pm_unblock(SAM0_UART_PM_BLOCK); - } + sercom_t sercom = sercom_id(uart_config[uart].dev); + DEBUG("[uart] powering off #%u on SERCOM%u\n", (unsigned)uart, (unsigned)sercom); + /* If we would release a SERCOM that we do not own, we could e.g. disable + * the SERCOM in the middle of an SPI or I2C transfer */ + if (!bf_isset(_enabled, uart)) { + return; } -#endif - dev(uart)->CTRLA.reg &= ~(SERCOM_USART_CTRLA_ENABLE); - irq_restore(state); - sercom_clk_dis(dev(uart)); + bf_unset_atomic(_enabled, uart); + + _detach_pins(uart); + sercom_release(sercom); } #ifdef MODULE_PERIPH_UART_COLLISION @@ -459,33 +455,33 @@ bool uart_collision_detected(uart_t uart) * will be in sync during disabling of TX, * then the flag will be set. */ - _syncbusy(dev(uart)); + _syncbusy(_dev(uart)); - bool collision = dev(uart)->STATUS.reg & SERCOM_USART_STATUS_COLL; - dev(uart)->STATUS.reg = SERCOM_USART_STATUS_COLL; + bool collision = _dev(uart)->STATUS.reg & SERCOM_USART_STATUS_COLL; + _dev(uart)->STATUS.reg = SERCOM_USART_STATUS_COLL; return collision; } void uart_collision_detect_enable(uart_t uart) { /* CTRLB is enable protected */ - dev(uart)->CTRLA.reg &= ~SERCOM_USART_CTRLA_ENABLE; - _syncbusy(dev(uart)); + _dev(uart)->CTRLA.reg &= ~SERCOM_USART_CTRLA_ENABLE; + _syncbusy(_dev(uart)); /* clear stale collision flag */ - dev(uart)->STATUS.reg = SERCOM_USART_STATUS_COLL; + _dev(uart)->STATUS.reg = SERCOM_USART_STATUS_COLL; /* enable collision detection */ - dev(uart)->CTRLB.reg |= SERCOM_USART_CTRLB_COLDEN; + _dev(uart)->CTRLB.reg |= SERCOM_USART_CTRLB_COLDEN; /* disable RX interrupt */ - dev(uart)->INTENCLR.reg = SERCOM_USART_INTENCLR_RXC; + _dev(uart)->INTENCLR.reg = SERCOM_USART_INTENCLR_RXC; /* re-enable UART */ - dev(uart)->CTRLA.reg |= SERCOM_USART_CTRLA_ENABLE; + _dev(uart)->CTRLA.reg |= SERCOM_USART_CTRLA_ENABLE; /* wait for config to be applied */ - _syncbusy(dev(uart)); + _syncbusy(_dev(uart)); } static void _drain_rxbuf(SercomUsart *dev) @@ -498,7 +494,7 @@ static void _drain_rxbuf(SercomUsart *dev) void uart_collision_detect_disable(uart_t uart) { - uint32_t ctrlb = dev(uart)->CTRLB.reg; + uint32_t ctrlb = _dev(uart)->CTRLB.reg; /* re-enable TX after collision */ ctrlb |= SERCOM_USART_CTRLB_TXEN; @@ -507,23 +503,23 @@ void uart_collision_detect_disable(uart_t uart) ctrlb &= ~SERCOM_USART_CTRLB_COLDEN; /* CTRLB is enable protected */ - dev(uart)->CTRLA.reg &= ~SERCOM_USART_CTRLA_ENABLE; - _syncbusy(dev(uart)); + _dev(uart)->CTRLA.reg &= ~SERCOM_USART_CTRLA_ENABLE; + _syncbusy(_dev(uart)); - dev(uart)->CTRLB.reg = ctrlb; + _dev(uart)->CTRLB.reg = ctrlb; /* re-enable UART */ - dev(uart)->CTRLA.reg |= SERCOM_USART_CTRLA_ENABLE; + _dev(uart)->CTRLA.reg |= SERCOM_USART_CTRLA_ENABLE; /* wait for config to be applied */ - _syncbusy(dev(uart)); + _syncbusy(_dev(uart)); /* clear bytes from RX buffer */ - _drain_rxbuf(dev(uart)); + _drain_rxbuf(_dev(uart)); /* re-enable RX complete IRQ */ if (uart_ctx[uart].rx_cb) { - dev(uart)->INTENSET.reg = SERCOM_USART_INTENSET_RXC; + _dev(uart)->INTENSET.reg = SERCOM_USART_INTENSET_RXC; } } #endif @@ -546,16 +542,16 @@ int uart_mode(uart_t uart, uart_data_bits_t data_bits, uart_parity_t parity, } /* Disable UART first to remove write protect */ - dev(uart)->CTRLA.reg &= ~SERCOM_USART_CTRLA_ENABLE; - _syncbusy(dev(uart)); + _dev(uart)->CTRLA.reg &= ~SERCOM_USART_CTRLA_ENABLE; + _syncbusy(_dev(uart)); - uint32_t ctrlb = dev(uart)->CTRLB.reg; + uint32_t ctrlb = _dev(uart)->CTRLB.reg; if (parity == UART_PARITY_NONE) { - dev(uart)->CTRLA.reg &= ~SERCOM_USART_CTRLA_FORM_Msk; + _dev(uart)->CTRLA.reg &= ~SERCOM_USART_CTRLA_FORM_Msk; } else { - dev(uart)->CTRLA.reg |= SERCOM_USART_CTRLA_FORM(1); + _dev(uart)->CTRLA.reg |= SERCOM_USART_CTRLA_FORM(1); if (parity == UART_PARITY_ODD) { ctrlb |= SERCOM_USART_CTRLB_PMODE; } @@ -571,12 +567,12 @@ int uart_mode(uart_t uart, uart_data_bits_t data_bits, uart_parity_t parity, ctrlb |= SERCOM_USART_CTRLB_SBMODE; } - dev(uart)->CTRLB.reg = ((ctrlb & ~SERCOM_USART_CTRLB_CHSIZE_Msk) | + _dev(uart)->CTRLB.reg = ((ctrlb & ~SERCOM_USART_CTRLB_CHSIZE_Msk) | SERCOM_USART_CTRLB_CHSIZE(data_bits)); /* Enable UART again */ - dev(uart)->CTRLA.reg |= SERCOM_USART_CTRLA_ENABLE; - _syncbusy(dev(uart)); + _dev(uart)->CTRLA.reg |= SERCOM_USART_CTRLA_ENABLE; + _syncbusy(_dev(uart)); return UART_OK; } @@ -586,45 +582,45 @@ int uart_mode(uart_t uart, uart_data_bits_t data_bits, uart_parity_t parity, void uart_rxstart_irq_configure(uart_t uart, uart_rxstart_cb_t cb, void *arg) { /* CTRLB is enable-proteced */ - dev(uart)->CTRLA.reg &= ~SERCOM_USART_CTRLA_ENABLE; + _dev(uart)->CTRLA.reg &= ~SERCOM_USART_CTRLA_ENABLE; /* set start of frame detection enable */ - dev(uart)->CTRLB.reg |= SERCOM_USART_CTRLB_SFDE; + _dev(uart)->CTRLB.reg |= SERCOM_USART_CTRLB_SFDE; uart_ctx[uart].rxs_cb = cb; uart_ctx[uart].rxs_arg = arg; /* enable UART again */ - dev(uart)->CTRLA.reg |= SERCOM_USART_CTRLA_ENABLE; + _dev(uart)->CTRLA.reg |= SERCOM_USART_CTRLA_ENABLE; } void uart_rxstart_irq_enable(uart_t uart) { /* clear stale interrupt flag */ - dev(uart)->INTFLAG.reg = SERCOM_USART_INTFLAG_RXS; + _dev(uart)->INTFLAG.reg = SERCOM_USART_INTFLAG_RXS; /* enable interrupt */ - dev(uart)->INTENSET.reg = SERCOM_USART_INTENSET_RXS; + _dev(uart)->INTENSET.reg = SERCOM_USART_INTENSET_RXS; } void uart_rxstart_irq_disable(uart_t uart) { - dev(uart)->INTENCLR.reg = SERCOM_USART_INTENCLR_RXS; + _dev(uart)->INTENCLR.reg = SERCOM_USART_INTENCLR_RXS; } #endif /* MODULE_PERIPH_UART_RXSTART_IRQ */ #ifdef MODULE_PERIPH_UART_NONBLOCKING -static inline void irq_handler_tx(unsigned uartnum) +static void irq_handler_tx(unsigned uartnum) { /* workaround for saml1x */ int c = tsrb_get_one(&uart_tx_rb[uartnum]); if (c >= 0) { - dev(uartnum)->DATA.reg = c; + _dev(uartnum)->DATA.reg = c; } /* disable the interrupt if there are no more bytes to send */ if (tsrb_empty(&uart_tx_rb[uartnum])) { - dev(uartnum)->INTENCLR.reg = SERCOM_USART_INTENSET_DRE; + _dev(uartnum)->INTENCLR.reg = SERCOM_USART_INTENSET_DRE; #if IS_ACTIVE(MODULE_PM_LAYERED) && defined(SAM0_UART_PM_BLOCK) /* we really should be in IRQ context! */ assert(irq_is_in()); @@ -634,118 +630,31 @@ static inline void irq_handler_tx(unsigned uartnum) } #endif -static inline void irq_handler(unsigned uartnum) +static void uart_isr(void *arg) { - uint32_t status = dev(uartnum)->INTFLAG.reg; + uart_t uart = (uintptr_t)arg; + SercomUsart *dev = _dev(uart); + uint32_t status = dev->INTFLAG.reg; /* TXC is used by uart_write() */ - dev(uartnum)->INTFLAG.reg = status & ~SERCOM_USART_INTFLAG_TXC; + dev->INTFLAG.reg = status & ~SERCOM_USART_INTFLAG_TXC; -#if !defined(UART_HAS_TX_ISR) && defined(MODULE_PERIPH_UART_NONBLOCKING) +#if MODULE_PERIPH_UART_NONBLOCKING if ((status & SERCOM_USART_INTFLAG_DRE) && - (dev(uartnum)->INTENSET.reg & SERCOM_USART_INTENSET_DRE)) { - irq_handler_tx(uartnum); + (dev->INTENSET.reg & SERCOM_USART_INTENSET_DRE)) { + irq_handler_tx(uart); } #endif #ifdef MODULE_PERIPH_UART_RXSTART_IRQ if ((status & SERCOM_USART_INTFLAG_RXS) && - (dev(uartnum)->INTENSET.reg & SERCOM_USART_INTENSET_RXS)) { - uart_ctx[uartnum].rxs_cb(uart_ctx[uartnum].rxs_arg); + (dev->INTENSET.reg & SERCOM_USART_INTENSET_RXS)) { + uart_ctx[uart].rxs_cb(uart_ctx[uart].rxs_arg); } #endif if (status & SERCOM_USART_INTFLAG_RXC) { /* interrupt flag is cleared by reading the data register */ - uart_ctx[uartnum].rx_cb(uart_ctx[uartnum].arg, - (uint8_t)(dev(uartnum)->DATA.reg)); + uart_ctx[uart].rx_cb(uart_ctx[uart].arg, dev->DATA.reg); } - cortexm_isr_end(); } - -#ifdef UART_0_ISR -void UART_0_ISR(void) -{ - irq_handler(0); -} -#endif - -#ifdef UART_1_ISR -void UART_1_ISR(void) -{ - irq_handler(1); -} -#endif - -#ifdef UART_2_ISR -void UART_2_ISR(void) -{ - irq_handler(2); -} -#endif - -#ifdef UART_3_ISR -void UART_3_ISR(void) -{ - irq_handler(3); -} -#endif - -#ifdef UART_4_ISR -void UART_4_ISR(void) -{ - irq_handler(4); -} -#endif - -#ifdef UART_5_ISR -void UART_5_ISR(void) -{ - irq_handler(5); -} -#endif - -#ifdef MODULE_PERIPH_UART_NONBLOCKING - -#ifdef UART_0_ISR_TX -void UART_0_ISR_TX(void) -{ - irq_handler_tx(0); -} -#endif - -#ifdef UART_1_ISR_TX -void UART_1_ISR_TX(void) -{ - irq_handler_tx(1); -} -#endif - -#ifdef UART_2_ISR_TX -void UART_2_ISR_TX(void) -{ - irq_handler_tx(2); -} -#endif - -#ifdef UART_3_ISR_TX -void UART_3_ISR_TX(void) -{ - irq_handler_tx(3); -} -#endif - -#ifdef UART_4_ISR_TX -void UART_4_ISR_TX(void) -{ - irq_handler_tx(4); -} -#endif - -#ifdef UART_5_ISR_TX -void UART_5_ISR_TX(void) -{ - irq_handler_tx(5); -} -#endif -#endif /* MODULE_PERIPH_UART_NONBLOCKING */ diff --git a/cpu/samd21/include/periph_cpu.h b/cpu/samd21/include/periph_cpu.h index 42260ccc8efd..e879c494c2d8 100644 --- a/cpu/samd21/include/periph_cpu.h +++ b/cpu/samd21/include/periph_cpu.h @@ -22,7 +22,7 @@ #include -#include "periph_cpu_common.h" +#include "periph_cpu_common.h" /* IWYU pragma: export */ #ifdef __cplusplus extern "C" { @@ -51,13 +51,8 @@ extern "C" { #define SAMD21_PM_IDLE_2 (1U) /**< Idle 2 (stops AHB, APB and CPU) */ #define SAMD21_PM_IDLE_1 (2U) /**< Idle 1 (stops AHB and CPU) */ #define SAMD21_PM_IDLE_0 (3U) /**< Idle 0 (stops CPU) */ -/** @} */ -/** - * @name SPI configuration - * @{ - */ -#define SAM0_SPI_PM_BLOCK SAMD21_PM_IDLE_1 /**< Stay in Idle 0 mode */ +#define SAM0_SERCOM_PM_BLOCK SAMD21_PM_IDLE_1 /**< Stay in Idle 0 mode */ /** @} */ /** @@ -99,6 +94,27 @@ static inline int _sercom_id(SercomUsart *sercom) return ((((uint32_t)sercom) >> 10) & 0x7) - 2; } +/* these functions are documented in periph_cpu_common.h, but Doxygen + * is unable to connect the dots */ +#if !DOXYGEN +static inline void sercom_apb_enable(sercom_t sercom) +{ + PM->APBCMASK.reg |= (PM_APBCMASK_SERCOM0 << sercom); +} + +static inline void sercom_apb_disable(sercom_t sercom) +{ + PM->APBCMASK.reg &= ~(PM_APBCMASK_SERCOM0 << sercom); +} + +static inline void sercom_gclk_enable(sercom_t sercom, uint8_t gclk) +{ + GCLK->CLKCTRL.reg = (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN(gclk) | + (SERCOM0_GCLK_ID_CORE + sercom)); + while (GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY) {} +} +#endif + /** * @brief Pins that can be used for ADC input */ diff --git a/cpu/samd5x/include/periph_cpu.h b/cpu/samd5x/include/periph_cpu.h index 07cf50987a88..52ca606f7fdf 100644 --- a/cpu/samd5x/include/periph_cpu.h +++ b/cpu/samd5x/include/periph_cpu.h @@ -23,7 +23,7 @@ #include #include "macros/units.h" -#include "periph_cpu_common.h" +#include "periph_cpu_common.h" /* IWYU pragma: export */ #include "candev_samd5x.h" #ifdef __cplusplus @@ -296,6 +296,41 @@ struct sam0_aux_cfg_mapping { #define SAM0_SDHC1_PIN_SDCK GPIO_PIN(PA, 21) /**< Clock */ /** @} */ +/* these functions are documented in periph_cpu_common.h, but Doxygen + * is unable to connect the dots */ +#if !DOXYGEN +static inline void sercom_apb_enable(sercom_t sercom) +{ + 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)); + } +} + +static inline void sercom_apb_disable(sercom_t sercom) +{ + 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)); + } +} + +static inline void sercom_gclk_enable(sercom_t sercom, uint8_t gclk) +{ + GCLK->PCHCTRL[_sercom_gclk_id_core(sercom)].reg = (GCLK_PCHCTRL_CHEN | GCLK_PCHCTRL_GEN(gclk)); +} +#endif + #ifdef __cplusplus } #endif diff --git a/cpu/saml1x/include/periph_cpu.h b/cpu/saml1x/include/periph_cpu.h index 81e8b10353bd..ea3a6002fa94 100644 --- a/cpu/saml1x/include/periph_cpu.h +++ b/cpu/saml1x/include/periph_cpu.h @@ -20,7 +20,7 @@ #ifndef PERIPH_CPU_H #define PERIPH_CPU_H -#include "periph_cpu_common.h" +#include "periph_cpu_common.h" /* IWYU pragma: export */ #ifdef __cplusplus extern "C" { @@ -136,7 +136,8 @@ struct sam0_aux_cfg_mapping { uint32_t reserved_2 : 19; /**< Reserved */ /* config word 2 */ uint32_t secure_flash_as_size : 8; /**< Secure Flash (AS region) Size = AS*0x100 */ - uint32_t nsc_size : 6; /**< Non-Secure Callable Flash (APPLICATION region) Size = ANSC*0x20 */ + uint32_t nsc_size : 6; /**< Non-Secure Callable Flash + * (APPLICATION region) Size = ANSC*0x20 */ uint32_t reserved_3 : 2; /**< Reserved */ uint32_t secure_flash_data_size : 4; /**< Secure Data Flash Size = DS*0x100 */ uint32_t reserved_4 : 4; /**< Reserved */ @@ -155,6 +156,25 @@ struct sam0_aux_cfg_mapping { uint32_t user_crc; /**< CRC of NVM User Row bits 223:64 (words 2…6) */ }; +/* these functions are documented in periph_cpu_common.h, but Doxygen + * is unable to connect the dots */ +#if !DOXYGEN +static inline void sercom_apb_enable(sercom_t sercom) +{ + MCLK->APBCMASK.reg |= (MCLK_APBCMASK_SERCOM0 << sercom); +} + +static inline void sercom_apb_disable(sercom_t sercom) +{ + MCLK->APBCMASK.reg &= ~(MCLK_APBCMASK_SERCOM0 << sercom); +} + +static inline void sercom_gclk_enable(sercom_t sercom, uint8_t gclk) +{ + GCLK->PCHCTRL[SERCOM0_GCLK_ID_CORE + sercom].reg = (GCLK_PCHCTRL_CHEN | GCLK_PCHCTRL_GEN(gclk)); +} +#endif + #ifdef __cplusplus } #endif diff --git a/cpu/saml21/include/periph_cpu.h b/cpu/saml21/include/periph_cpu.h index 4476603de15f..b37ec7bde6ef 100644 --- a/cpu/saml21/include/periph_cpu.h +++ b/cpu/saml21/include/periph_cpu.h @@ -20,7 +20,7 @@ #ifndef PERIPH_CPU_H #define PERIPH_CPU_H -#include "periph_cpu_common.h" +#include "periph_cpu_common.h" /* IWYU pragma: export */ #ifdef __cplusplus extern "C" { @@ -47,9 +47,8 @@ extern "C" { */ #define SAM0_GPIO_PM_BLOCK SAML21_PM_MODE_BACKUP /**< GPIO IRQs require STANDBY mode */ #define SAM0_RTCRTT_PM_BLOCK SAML21_PM_MODE_BACKUP /**< RTC/TRR require STANDBY mode */ -#define SAM0_SPI_PM_BLOCK SAML21_PM_MODE_STANDBY /**< SPI in DMA mode require IDLE mode */ +#define SAM0_SERCOM_PM_BLOCK SAML21_PM_MODE_STANDBY /**< SERCOMs require IDLE mode */ #define SAM0_TIMER_PM_BLOCK SAML21_PM_MODE_STANDBY /**< Timers require IDLE mode */ -#define SAM0_UART_PM_BLOCK SAML21_PM_MODE_STANDBY /**< UART RX IRQ require IDLE mode */ #define SAM0_USB_IDLE_PM_BLOCK SAML21_PM_MODE_BACKUP /**< Idle USB require STANDBY mode */ #define SAM0_USB_ACTIVE_PM_BLOCK SAML21_PM_MODE_STANDBY /**< Active USB require IDLE mode */ /** @} */ @@ -170,6 +169,41 @@ struct sam0_aux_cfg_mapping { }; /** @} */ +/* these functions are documented in periph_cpu_common.h, but Doxygen + * is unable to connect the dots */ +#if !DOXYGEN +static inline void sercom_apb_enable(sercom_t sercom) +{ + if (sercom < 5) { + MCLK->APBCMASK.reg |= (MCLK_APBCMASK_SERCOM0 << sercom); + } + else { + MCLK->APBDMASK.reg |= (MCLK_APBDMASK_SERCOM5); + } +} + +static inline void sercom_apb_disable(sercom_t sercom) +{ + if (sercom < 5) { + MCLK->APBCMASK.reg &= ~(MCLK_APBCMASK_SERCOM0 << sercom); + } + else { + MCLK->APBDMASK.reg &= ~(MCLK_APBDMASK_SERCOM5); + } +} + +static inline void sercom_gclk_enable(sercom_t sercom, uint8_t gclk) +{ + uint32_t val = (GCLK_PCHCTRL_CHEN | GCLK_PCHCTRL_GEN(gclk)); + if (sercom < 5) { + GCLK->PCHCTRL[SERCOM0_GCLK_ID_CORE + sercom].reg = val; + } + else { + GCLK->PCHCTRL[SERCOM5_GCLK_ID_CORE].reg = val; + } +} +#endif + #ifdef __cplusplus } #endif diff --git a/features.yaml b/features.yaml index f40c454a95f0..5a1da2b492c9 100644 --- a/features.yaml +++ b/features.yaml @@ -815,6 +815,8 @@ groups: help: A RISC-V Core-local Interrupt Controller (CLIC) peripheral is present. - name: periph_plic help: A RISC-V Platform-local Interrupt Controller (PLIC) peripheral is present. + - name: periph_sercom + help: A SAM0 SERial COMmunication peripheral is present. - title: Cryptographic Features help: Hardware acceleration for cryptographic primitives, hardware random diff --git a/makefiles/features_existing.inc.mk b/makefiles/features_existing.inc.mk index fc1c34926bee..d9bf56158394 100644 --- a/makefiles/features_existing.inc.mk +++ b/makefiles/features_existing.inc.mk @@ -226,6 +226,7 @@ FEATURES_EXISTING := \ periph_sdmmc_hs \ periph_sdmmc_mmc \ periph_sdmmc_sdhc \ + periph_sercom \ periph_spi \ periph_spi_gpio_mode \ periph_spi_on_qspi \