From 73a2810330d112be3536d5e15f24c5e2d293338f Mon Sep 17 00:00:00 2001 From: PeterKietzmann Date: Wed, 20 Dec 2017 13:54:32 +0100 Subject: [PATCH] drivers/kw2xrf: finish ongoing transmission before sending next frame --- drivers/Makefile.dep | 1 + drivers/include/kw2xrf.h | 2 + drivers/kw2xrf/kw2xrf_netdev.c | 72 ++++++++++++++++++++++++++++------ 3 files changed, 62 insertions(+), 13 deletions(-) diff --git a/drivers/Makefile.dep b/drivers/Makefile.dep index 053d54a3c7..4ae01b7f60 100644 --- a/drivers/Makefile.dep +++ b/drivers/Makefile.dep @@ -142,6 +142,7 @@ ifneq (,$(filter kw2xrf,$(USEMODULE))) USEMODULE += netif USEMODULE += ieee802154 USEMODULE += netdev_ieee802154 + USEMODULE += core_thread_flags FEATURES_REQUIRED += periph_spi endif diff --git a/drivers/include/kw2xrf.h b/drivers/include/kw2xrf.h index da6efae165..5baa074624 100644 --- a/drivers/include/kw2xrf.h +++ b/drivers/include/kw2xrf.h @@ -31,6 +31,7 @@ #include "net/netdev.h" #include "net/netdev/ieee802154.h" #include "net/gnrc/nettype.h" +#include "thread.h" #ifdef __cplusplus extern "C" { @@ -129,6 +130,7 @@ typedef struct { * @brief device specific fields * @{ */ + thread_t *thread; /**< Network driver thread, for providing feedback from IRQ handler */ kw2xrf_params_t params; /**< parameters for initialization */ uint8_t buf[KW2XRF_MAX_PKT_LENGTH]; /**< Buffer for incoming or outgoing packets */ uint8_t state; /**< current state of the radio */ diff --git a/drivers/kw2xrf/kw2xrf_netdev.c b/drivers/kw2xrf/kw2xrf_netdev.c index e0f65d5e17..4d8a0dd3be 100644 --- a/drivers/kw2xrf/kw2xrf_netdev.c +++ b/drivers/kw2xrf/kw2xrf_netdev.c @@ -1,5 +1,7 @@ /* * Copyright (C) 2016 Phytec Messtechnik GmbH + 2017 HAW Hamburg + 2017 SKF AB * * 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 @@ -13,7 +15,9 @@ * @file * @brief Netdev interface for kw2xrf drivers * - * @author Johann Fischer + * @author Johann Fischer + * @author Peter Kietzmann + * @author Joakim NohlgÄrd */ #include @@ -21,6 +25,7 @@ #include #include "log.h" +#include "thread_flags.h" #include "net/eui64.h" #include "net/ieee802154.h" #include "net/netdev.h" @@ -41,14 +46,28 @@ #define _MACACKWAITDURATION (864 / 16) /* 864us * 62500Hz */ +#define KW2XRF_THREAD_FLAG_ISR (1 << 8) + +static volatile unsigned int num_irqs_queued = 0; +static volatile unsigned int num_irqs_handled = 0; +static unsigned int spinning_for_irq = 0; static uint8_t _send_last_fcf; +static void _isr(netdev_t *netdev); + static void _irq_handler(void *arg) { - netdev_t *dev = (netdev_t *) arg; + netdev_t *netdev = (netdev_t *) arg; + kw2xrf_t *dev = (kw2xrf_t *)netdev; - if (dev->event_callback) { - dev->event_callback(dev, NETDEV_EVENT_ISR); + thread_flags_set(dev->thread, KW2XRF_THREAD_FLAG_ISR); + + /* We use this counter to avoid filling the message queue with redundant ISR events */ + if (num_irqs_queued == num_irqs_handled) { + ++num_irqs_queued; + if (netdev->event_callback) { + netdev->event_callback(netdev, NETDEV_EVENT_ISR); + } } } @@ -56,6 +75,8 @@ static int _init(netdev_t *netdev) { kw2xrf_t *dev = (kw2xrf_t *)netdev; + dev->thread = (thread_t *)thread_get(thread_getpid()); + /* initialize SPI and GPIOs */ if (kw2xrf_init(dev, &_irq_handler)) { LOG_ERROR("[kw2xrf] unable to initialize device\n"); @@ -91,6 +112,32 @@ static void kw2xrf_tx_exec(kw2xrf_t *dev) } } +static void kw2xrf_wait_idle(kw2xrf_t *dev) +{ + /* make sure any ongoing T or TR sequence is finished */ + if (kw2xrf_can_switch_to_idle(dev) == 0) { + DEBUG("[kw2xrf] TX already in progress\n"); + num_irqs_handled = num_irqs_queued; + spinning_for_irq = 1; + thread_flags_clear(KW2XRF_THREAD_FLAG_ISR); + while (1) { + /* TX in progress */ + /* Handle any outstanding IRQ first */ + _isr((netdev_t *)dev); + /* _isr() will switch the transceiver back to idle after + * handling the TX complete IRQ */ + if (kw2xrf_can_switch_to_idle(dev)) { + break; + } + /* Block until we get another IRQ */ + thread_flags_wait_any(KW2XRF_THREAD_FLAG_ISR); + DEBUG("[kw2xrf] waited ISR\n"); + } + spinning_for_irq = 0; + DEBUG("[kw2xrf] previous TX done\n"); + } +} + static int _send(netdev_t *netdev, const struct iovec *vector, unsigned count) { kw2xrf_t *dev = (kw2xrf_t *)netdev; @@ -98,6 +145,9 @@ static int _send(netdev_t *netdev, const struct iovec *vector, unsigned count) uint8_t *pkt_buf = &(dev->buf[1]); size_t len = 0; + /* wait for ongoing transmissions to finish */ + kw2xrf_wait_idle(dev); + /* load packet data into buffer */ for (unsigned i = 0; i < count; i++, ptr++) { /* current packet data + FCS too long */ @@ -109,15 +159,8 @@ static int _send(netdev_t *netdev, const struct iovec *vector, unsigned count) len = kw2xrf_tx_load(pkt_buf, ptr->iov_base, ptr->iov_len, len); } - /* make sure ongoing t or tr sequenz are finished */ - if (kw2xrf_can_switch_to_idle(dev)) { - kw2xrf_set_sequence(dev, XCVSEQ_IDLE); - dev->pending_tx++; - } - else { - /* do not wait, this can lead to a dead lock */ - return 0; - } + kw2xrf_set_sequence(dev, XCVSEQ_IDLE); + dev->pending_tx++; /* * Nbytes = FRAME_LEN - 2 -> FRAME_LEN = Nbytes + 2 @@ -690,6 +733,9 @@ static void _isr(netdev_t *netdev) { uint8_t dregs[MKW2XDM_PHY_CTRL4 + 1]; kw2xrf_t *dev = (kw2xrf_t *)netdev; + if (!spinning_for_irq) { + num_irqs_handled = num_irqs_queued; + } kw2xrf_read_dregs(dev, MKW2XDM_IRQSTS1, dregs, MKW2XDM_PHY_CTRL4 + 1); kw2xrf_mask_irq_b(dev);