1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00

Merge pull request #16681 from benpicco/drivers/dose-collision

drivers/dose: make use of UART collision detection feature
This commit is contained in:
benpicco 2021-12-08 20:48:28 +01:00 committed by GitHub
commit e8cbf1ea90
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 186 additions and 3 deletions

View File

@ -340,6 +340,82 @@ void uart_poweroff(uart_t uart)
sercom_clk_dis(dev(uart));
}
#ifdef MODULE_PERIPH_UART_COLLISION
bool uart_collision_detected(uart_t uart)
{
/* In case of collision, the CTRLB register
* will be in sync during disabling of TX,
* then the flag will be set.
*/
_syncbusy(dev(uart));
bool collision = dev(uart)->STATUS.bit.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.bit.ENABLE = 0;
_syncbusy(dev(uart));
/* clear stale collision flag */
dev(uart)->STATUS.reg = SERCOM_USART_STATUS_COLL;
/* enable collision detection */
dev(uart)->CTRLB.bit.COLDEN = 1;
/* disable RX interrupt */
dev(uart)->INTENCLR.bit.RXC = 1;
/* re-enable UART */
dev(uart)->CTRLA.bit.ENABLE = 1;
/* wait for config to be applied */
_syncbusy(dev(uart));
}
static void _drain_rxbuf(SercomUsart *dev)
{
/* clear readback bytes from receive buffer */
while (dev->INTFLAG.bit.RXC) {
dev->DATA.reg;
}
}
void uart_collision_detect_disable(uart_t uart)
{
uint32_t ctrlb = dev(uart)->CTRLB.reg;
/* re-enable TX after collision */
ctrlb |= SERCOM_USART_CTRLB_TXEN;
/* disable collision detection */
ctrlb &= ~SERCOM_USART_CTRLB_COLDEN;
/* CTRLB is enable protected */
dev(uart)->CTRLA.bit.ENABLE = 0;
_syncbusy(dev(uart));
dev(uart)->CTRLB.reg = ctrlb;
/* re-enable UART */
dev(uart)->CTRLA.bit.ENABLE = 1;
/* wait for config to be applied */
_syncbusy(dev(uart));
/* clear bytes from RX buffer */
_drain_rxbuf(dev(uart));
/* re-enable RX complete IRQ */
if (uart_ctx[uart].rx_cb) {
dev(uart)->INTENSET.bit.RXC = 1;
}
}
#endif
#ifdef MODULE_PERIPH_UART_MODECFG
int uart_mode(uart_t uart, uart_data_bits_t data_bits, uart_parity_t parity,
uart_stop_bits_t stop_bits)

View File

@ -16,6 +16,7 @@ config CPU_FAM_SAMD10
bool
select CPU_COMMON_SAMD21
select HAS_PERIPH_DMA
select HAS_PERIPH_UART_COLLISION
config CPU_FAM_SAMD20
bool
@ -25,11 +26,13 @@ config CPU_FAM_SAMD21
bool
select CPU_COMMON_SAMD21
select HAS_PERIPH_DMA
select HAS_PERIPH_UART_COLLISION
config CPU_FAM_SAMR21
bool
select CPU_COMMON_SAMD21
select HAS_PERIPH_DMA
select HAS_PERIPH_UART_COLLISION
## Definition of specific features
config HAS_CPU_SAMD21

View File

@ -2,4 +2,8 @@ CPU_CORE = cortex-m0plus
FEATURES_PROVIDED += periph_gpio_fast_read
ifeq (,$(filter samd20%,$(CPU_MODEL)))
FEATURES_PROVIDED += periph_uart_collision
endif
-include $(RIOTCPU)/sam0_common/Makefile.features

View File

@ -16,6 +16,7 @@ config CPU_COMMON_SAMD5X
select HAS_PERIPH_GPIO_TAMPER_WAKE
select HAS_PERIPH_HWRNG
select HAS_PERIPH_RTC_MEM
select HAS_PERIPH_UART_COLLISION
select HAS_PERIPH_SPI_ON_QSPI
config CPU_FAM_SAMD51

View File

@ -6,5 +6,6 @@ FEATURES_PROVIDED += cortexm_mpu
FEATURES_PROVIDED += periph_gpio_tamper_wake
FEATURES_PROVIDED += periph_rtc_mem
FEATURES_PROVIDED += periph_spi_on_qspi
FEATURES_PROVIDED += periph_uart_collision
include $(RIOTCPU)/sam0_common/Makefile.features

View File

@ -13,6 +13,7 @@ config CPU_COMMON_SAML1X
select HAS_PERIPH_DMA
select HAS_PERIPH_GPIO_FAST_READ
select HAS_PERIPH_HWRNG
select HAS_PERIPH_UART_COLLISION
config CPU_FAM_SAML10
bool

View File

@ -5,5 +5,6 @@ CPU_CORE = cortex-m23
FEATURES_PROVIDED += periph_hwrng
FEATURES_PROVIDED += periph_gpio_fast_read
FEATURES_PROVIDED += periph_uart_collision
include $(RIOTCPU)/sam0_common/Makefile.features

View File

@ -14,6 +14,7 @@ config CPU_COMMON_SAML21
select HAS_PERIPH_DMA
select HAS_PERIPH_GPIO_FAST_READ
select HAS_PERIPH_RTC_MEM
select HAS_PERIPH_UART_COLLISION
config CPU_FAM_SAML21
bool

View File

@ -4,6 +4,7 @@ CPU_CORE = cortex-m0plus
CPU_MODELS_WITHOUT_HWRNG += samr30%
FEATURES_PROVIDED += periph_gpio_fast_read
FEATURES_PROVIDED += periph_uart_collision
# Low Power SRAM is *not* retained during Backup Sleep.
# It therefore does not fulfill the requirements of the 'backup_ram' interface.

View File

@ -1,5 +1,6 @@
FEATURES_REQUIRED += periph_gpio_irq
FEATURES_REQUIRED += periph_uart
FEATURES_OPTIONAL += periph_uart_collision
FEATURES_OPTIONAL += periph_uart_rxstart_irq
USEMODULE += eui_provider

View File

@ -202,9 +202,9 @@ static dose_signal_t state_transit_send(dose_t *ctx, dose_signal_t signal)
/* Don't trace any END octets ... the timeout or the END signal
* will bring us back to the BLOCKED state after _send has emitted
* its last octet. */
#ifndef MODULE_PERIPH_UART_COLLISION
xtimer_set(&ctx->timeout, ctx->timeout_base);
#endif
return DOSE_SIGNAL_NONE;
}
@ -399,6 +399,10 @@ static int send_octet(dose_t *ctx, uint8_t c)
{
uart_write(ctx->uart, (uint8_t *) &c, sizeof(c));
#ifdef MODULE_PERIPH_UART_COLLISION
return uart_collision_detected(ctx->uart);
#endif
/* Wait for a state transition */
uint8_t new_state = wait_for_state(ctx, DOSE_STATE_ANY);
if (new_state != DOSE_STATE_SEND) {
@ -433,6 +437,28 @@ static int send_data_octet(dose_t *ctx, uint8_t c)
return rc;
}
static inline void _send_start(dose_t *ctx)
{
#ifdef MODULE_PERIPH_UART_COLLISION
uart_collision_detect_enable(ctx->uart);
#else
(void)ctx;
#endif
}
static inline void _send_done(dose_t *ctx, bool collision)
{
#ifdef MODULE_PERIPH_UART_COLLISION
uart_collision_detect_disable(ctx->uart);
if (collision) {
state(ctx, DOSE_SIGNAL_XTIMER);
}
#else
(void)ctx;
(void)collision;
#endif
}
static int _send(netdev_t *dev, const iolist_t *iolist)
{
dose_t *ctx = container_of(dev, dose_t, netdev);
@ -460,6 +486,8 @@ send:
state(ctx, DOSE_SIGNAL_SEND);
} while (wait_for_state(ctx, DOSE_STATE_ANY) != DOSE_STATE_SEND);
_send_start(ctx);
/* Send packet buffer */
for (const iolist_t *iol = iolist; iol; iol = iol->iol_next) {
size_t n = iol->iol_len;
@ -492,6 +520,8 @@ send:
goto collision;
}
_send_done(ctx, false);
/* We probably sent the whole packet?! */
dev->event_callback(dev, NETDEV_EVENT_TX_COMPLETE);
@ -501,11 +531,13 @@ send:
return pktlen;
collision:
_send_done(ctx, true);
DEBUG("dose _send(): collision!\n");
if (--retries < 0) {
dev->event_callback(dev, NETDEV_EVENT_TX_MEDIUM_BUSY);
return -EBUSY;
}
goto send;
}

View File

@ -296,6 +296,48 @@ void uart_rxstart_irq_enable(uart_t uart);
void uart_rxstart_irq_disable(uart_t uart);
#endif /* MODULE_PERIPH_UART_RXSTART_IRQ */
#if defined(MODULE_PERIPH_UART_COLLISION) || DOXYGEN
/**
* @brief Enables collision detection check of the UART.
* This assumes the UART is connected to a bus where RX and TX are
* connected. After each sent byte it is checked whether the same
* byte could be received.
*
* This disables the RX interrupt.
*
* @note You have to add the module `periph_uart_rxstart_irq` to your project
* to enable this function
*
* @param[in] uart The device to configure
*/
void uart_collision_detect_enable(uart_t uart);
/**
* @brief Disables collision detection check of the UART.
*
* If an RX interrupt was configured before, it is enabled again.
*
* @note You have to add the module `periph_uart_rxstart_irq` to your project
* to enable this function
*
* @param[in] uart The device to configure
*/
void uart_collision_detect_disable(uart_t uart);
/**
* @brief Disables collision detection check of the UART.
*
* If an RX interrupt was configured before, it is enabled again.
*
* @note You have to add the module `periph_uart_rxstart_irq` to your project
* to enable this function
*
* @param[in] uart The device to probe
*
* @return true if a collision occurred during the last transder
*/
bool uart_collision_detected(uart_t uart);
#endif /* MODULE_PERIPH_UART_COLLISION */
/**
* @brief Setup parity, data and stop bits for a given UART device
*

View File

@ -28,6 +28,10 @@ config MODULE_PERIPH_LPUART
bool "Enable Low Power UART (LPUART)"
depends on HAS_PERIPH_LPUART
config MODULE_PERIPH_UART_COLLISION
bool "Enable UART collision detection"
depends on HAS_PERIPH_UART_COLLISION
config MODULE_PERIPH_UART_NONBLOCKING
bool "Non-blocking support"
depends on HAS_PERIPH_UART_NONBLOCKING

View File

@ -323,6 +323,11 @@ config HAS_PERIPH_UART
help
Indicates that an UART peripheral is present.
config HAS_PERIPH_UART_COLLISION
bool
help
Indicates that the UART peripheral supports hardware collision detection.
config HAS_PERIPH_UART_HW_FC
bool
help

View File

@ -1,4 +1,4 @@
# the driver to test
USEMODULE = dose
USEMODULE += dose
include ../driver_netdev_common/Makefile.netdev.mk

View File

@ -11,4 +11,5 @@ config APPLICATION
imply MODULE_PERIPH_UART_MODECFG
imply MODULE_PERIPH_LPUART
imply MODULE_PERIPH_UART_RXSTART_IRQ
imply MODULE_PERIPH_UART_COLLISION
depends on TEST_KCONFIG

View File

@ -2,6 +2,7 @@ include ../Makefile.tests_common
FEATURES_REQUIRED += periph_uart
FEATURES_OPTIONAL += periph_lpuart # STM32 L0 and L4 provides lpuart support
FEATURES_OPTIONAL += periph_uart_collision
FEATURES_OPTIONAL += periph_uart_modecfg
FEATURES_OPTIONAL += periph_uart_rxstart_irq

View File

@ -151,6 +151,14 @@ static int _self_test(uart_t dev, unsigned baud)
}
uart_rxstart_irq_disable(dev);
#endif
#ifdef MODULE_PERIPH_UART_COLLISION
uart_collision_detect_enable(dev);
uart_write(dev, (uint8_t*)test_string, sizeof(test_string));
if (uart_collision_detected(dev)) {
printf("collision detected\n");
}
uart_collision_detect_disable(dev);
#endif
test_mode = false;
return 0;