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:
commit
e8cbf1ea90
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
*
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -1,4 +1,4 @@
|
||||
# the driver to test
|
||||
USEMODULE = dose
|
||||
USEMODULE += dose
|
||||
|
||||
include ../driver_netdev_common/Makefile.netdev.mk
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user