drivers/ieee802154_kw41z: Stabilize the KW41Z IEEE802.15.4 driver
- Reworked the driver logic around TX/RX to correctly handle the
expectations of the underlying 802.15.4 hardware IP.
- Fixed a problem with TX always reporting an error to the stack
which resulted in constant retries.
- Fixed bug in RX to TX transition which would occasionally cause the
driver to error the TX.
- Changed RX logic to ensure that invalid RX frames were not passed up
the stack.
- Simplified hardware timer usage to only use TMR3.
- Added RX watermark and TMR3 support to fix a hardware problem where
the hw IP can get stuck on a receive in noisy environments.
- Modified samples/net/echo_client and echo_server kw41z project config
files to provide enanced debug visibility into stacks and threads.
Signed-off-by: David Leach <david.leach@nxp.com>
diff --git a/drivers/ieee802154/ieee802154_kw41z.c b/drivers/ieee802154/ieee802154_kw41z.c
index 58bad92..bbafee6 100644
--- a/drivers/ieee802154/ieee802154_kw41z.c
+++ b/drivers/ieee802154/ieee802154_kw41z.c
@@ -29,7 +29,6 @@
#define KW41Z_SHR_PHY_TIME 12
#define KW41Z_PER_BYTE_TIME 2
#define KW41Z_ACK_WAIT_TIME 54
-#define KW41Z_IDLE_WAIT_RETRIES 5
#define KW41Z_PRE_RX_WAIT_TIME 1
#define KW40Z_POST_SEQ_WAIT_TIME 1
@@ -38,15 +37,33 @@
#define KW41Z_PSDU_LENGTH 125
#define KW41Z_OUTPUT_POWER_MAX 2
#define KW41Z_OUTPUT_POWER_MIN (-19)
-#define KW41Z_AUTOACK_ENABLED 1
+/*
+ * When ACK offload is implemented in the 15.4 stack we can enable
+ * things here.
+ */
+#define KW41Z_AUTOACK_ENABLED 0
+
+#define BM_ZLL_IRQSTS_TMRxMSK (ZLL_IRQSTS_TMR1MSK_MASK | \
+ ZLL_IRQSTS_TMR2MSK_MASK | \
+ ZLL_IRQSTS_TMR3MSK_MASK | \
+ ZLL_IRQSTS_TMR4MSK_MASK)
+
+/*
+ * Clear channel assement types. Note that there is an extra one when
+ * bit 26 is included for "No CCA before transmit" if we are handling
+ * ACK frames but we will let the hardware handle that automatically.
+ */
enum {
- KW41Z_CCA_ED,
- KW41Z_CCA_MODE1,
- KW41Z_CCA_MODE2,
- KW41Z_CCA_MODE3
+ KW41Z_CCA_ED, /* Energy detect */
+ KW41Z_CCA_MODE1, /* Energy above threshold */
+ KW41Z_CCA_MODE2, /* Carrier sense only */
+ KW41Z_CCA_MODE3 /* Mode 1 + Mode 2 */
};
+/*
+ * KW41Z has a sequencer that can run in any of the following states.
+ */
enum {
KW41Z_STATE_IDLE,
KW41Z_STATE_RX,
@@ -112,12 +129,9 @@
static inline void kw41z_wait_for_idle(void)
{
- u8_t retries = KW41Z_IDLE_WAIT_RETRIES;
u8_t state = kw41z_get_instant_state();
-
- while (state != KW41Z_STATE_IDLE && retries) {
- retries--;
+ while (state != KW41Z_STATE_IDLE) {
state = kw41z_get_instant_state();
}
@@ -126,19 +140,103 @@
}
}
-static int kw41z_prepare_for_new_state(void)
+static void kw41z_phy_abort(void)
{
- if (kw41z_get_seq_state() == KW41Z_STATE_RX) {
- kw41z_set_seq_state(KW41Z_STATE_IDLE);
+ int key;
+
+ key = irq_lock();
+
+ /* Mask SEQ interrupt */
+ ZLL->PHY_CTRL |= ZLL_PHY_CTRL_SEQMSK_MASK;
+ /* Disable timer trigger (for scheduled XCVSEQ) */
+ if (ZLL->PHY_CTRL & ZLL_PHY_CTRL_TMRTRIGEN_MASK) {
+ ZLL->PHY_CTRL &= ~ZLL_PHY_CTRL_TMRTRIGEN_MASK;
+ /* give the FSM enough time to start if it was triggered */
+ while ((XCVR_MISC->XCVR_CTRL &
+ XCVR_CTRL_XCVR_STATUS_TSM_COUNT_MASK) == 0) {
+ }
}
- if (kw41z_get_seq_state() != KW41Z_STATE_IDLE) {
- return -1;
+ /* If XCVR is not idle, abort current SEQ */
+ if (ZLL->PHY_CTRL & ZLL_PHY_CTRL_XCVSEQ_MASK) {
+ ZLL->PHY_CTRL &= ~ZLL_PHY_CTRL_XCVSEQ_MASK;
+ /* wait for Sequence Idle (if not already) */
+
+ while (ZLL->SEQ_STATE & ZLL_SEQ_STATE_SEQ_STATE_MASK) {
+ }
}
- kw41z_wait_for_idle();
+ /* Stop timers */
+ ZLL->PHY_CTRL &= ~(ZLL_PHY_CTRL_TMR1CMP_EN_MASK |
+ ZLL_PHY_CTRL_TMR2CMP_EN_MASK |
+ ZLL_PHY_CTRL_TMR3CMP_EN_MASK |
+ ZLL_PHY_CTRL_TC3TMOUT_MASK);
- return 0;
+ /*
+ * Clear all IRQ bits to avoid unexpected interrupts.
+ *
+ * For Coverity, this is a pointer to a register bank and the IRQSTS
+ * register bits get cleared when a 1 is written to them so doing a
+ * reg=reg may generate a warning but it is needed to clear the bits.
+ */
+ ZLL->IRQSTS = ZLL->IRQSTS;
+
+ irq_unlock(key);
+}
+
+static void kw41z_isr_timeout_cleanup(void)
+{
+ u32_t irqsts;
+
+ /*
+ * Set the PHY sequencer back to IDLE and disable TMR3 comparator
+ * and timeout
+ */
+ ZLL->PHY_CTRL &= ~(ZLL_PHY_CTRL_TMR3CMP_EN_MASK |
+ ZLL_PHY_CTRL_TC3TMOUT_MASK |
+ ZLL_PHY_CTRL_XCVSEQ_MASK);
+
+ /* Mask SEQ, RX, TX and CCA interrupts */
+ ZLL->PHY_CTRL |= ZLL_PHY_CTRL_CCAMSK_MASK |
+ ZLL_PHY_CTRL_RXMSK_MASK |
+ ZLL_PHY_CTRL_TXMSK_MASK |
+ ZLL_PHY_CTRL_SEQMSK_MASK;
+
+ while (ZLL->SEQ_STATE & ZLL_SEQ_STATE_SEQ_STATE_MASK) {
+ }
+
+ irqsts = ZLL->IRQSTS;
+ /* Mask TMR3 interrupt */
+ irqsts |= ZLL_IRQSTS_TMR3MSK_MASK;
+
+ ZLL->IRQSTS = irqsts;
+}
+
+static void kw41z_isr_seq_cleanup(void)
+{
+ u32_t irqsts;
+
+ /* Set the PHY sequencer back to IDLE */
+ ZLL->PHY_CTRL &= ~ZLL_PHY_CTRL_XCVSEQ_MASK;
+ /* Mask SEQ, RX, TX and CCA interrupts */
+ ZLL->PHY_CTRL |= ZLL_PHY_CTRL_CCAMSK_MASK |
+ ZLL_PHY_CTRL_RXMSK_MASK |
+ ZLL_PHY_CTRL_TXMSK_MASK |
+ ZLL_PHY_CTRL_SEQMSK_MASK;
+
+ while (ZLL->SEQ_STATE & ZLL_SEQ_STATE_SEQ_STATE_MASK) {
+ }
+
+ irqsts = ZLL->IRQSTS;
+ /* Mask TMR3 interrupt */
+ irqsts |= ZLL_IRQSTS_TMR3MSK_MASK;
+
+ /* Clear transceiver interrupts except TMRxIRQ */
+ irqsts &= ~(ZLL_IRQSTS_TMR1IRQ_MASK |
+ ZLL_IRQSTS_TMR2IRQ_MASK |
+ ZLL_IRQSTS_TMR3IRQ_MASK |
+ ZLL_IRQSTS_TMR4IRQ_MASK);
+ ZLL->IRQSTS = irqsts;
}
static inline void kw41z_enable_seq_irq(void)
@@ -151,42 +249,50 @@
ZLL->PHY_CTRL |= ZLL_PHY_CTRL_SEQMSK_MASK;
}
-static void kw41z_tmr1_set_timeout(u32_t timeout)
+/*
+ * Set the T3CMP timer comparator. The 'timeout' value is an offset from
+ * now.
+ */
+static void kw41z_tmr3_set_timeout(u32_t timeout)
{
+ u32_t irqsts;
+
+ /* Add in the current time so that we can get the comparator to
+ * match appropriately to our offset time.
+ */
timeout += ZLL->EVENT_TMR >> ZLL_EVENT_TMR_EVENT_TMR_SHIFT;
- ZLL->PHY_CTRL &= ~ZLL_PHY_CTRL_TMR1CMP_EN_MASK;
+ /* disable TMR3 compare */
+ ZLL->PHY_CTRL &= ~ZLL_PHY_CTRL_TMR3CMP_EN_MASK;
+ ZLL->T3CMP = timeout & ZLL_T3CMP_T3CMP_MASK;
- ZLL->T1CMP = timeout;
- ZLL->IRQSTS = (ZLL->IRQSTS & ~ZLL_IRQSTS_TMR1MSK_MASK) |
- ZLL_IRQSTS_TMR1IRQ_MASK;
-
- ZLL->PHY_CTRL |= ZLL_PHY_CTRL_TMR1CMP_EN_MASK;
+ /* aknowledge TMR3 IRQ */
+ irqsts = ZLL->IRQSTS & BM_ZLL_IRQSTS_TMRxMSK;
+ irqsts |= ZLL_IRQSTS_TMR3IRQ_MASK;
+ ZLL->IRQSTS = irqsts;
+ /* enable TMR3 compare */
+ ZLL->PHY_CTRL |= ZLL_PHY_CTRL_TMR3CMP_EN_MASK;
+ /* enable autosequence stop by TC3 match */
+ ZLL->PHY_CTRL |= ZLL_PHY_CTRL_TC3TMOUT_MASK;
}
-static inline void kw41z_tmr1_disable(void)
+static void kw41z_tmr3_disable(void)
{
- ZLL->IRQSTS |= ZLL_IRQSTS_TMR1MSK_MASK;
- ZLL->PHY_CTRL &= ~ZLL_PHY_CTRL_TMR1CMP_EN_MASK;
-}
+ u32_t irqsts;
-static void kw41z_tmr2_set_timeout(u32_t timeout)
-{
- timeout += ZLL->EVENT_TMR >> ZLL_EVENT_TMR_EVENT_TMR_SHIFT;
+ /*
+ * disable TMR3 compare and disable autosequence stop by TC3
+ * match
+ */
+ ZLL->PHY_CTRL &= ~(ZLL_PHY_CTRL_TMR3CMP_EN_MASK |
+ ZLL_PHY_CTRL_TC3TMOUT_MASK);
+ /* mask TMR3 interrupt (do not change other IRQ status) */
+ irqsts = ZLL->IRQSTS & BM_ZLL_IRQSTS_TMRxMSK;
+ irqsts |= ZLL_IRQSTS_TMR3MSK_MASK;
+ /* aknowledge TMR3 IRQ */
+ irqsts |= ZLL_IRQSTS_TMR3IRQ_MASK;
- ZLL->PHY_CTRL &= ~ZLL_PHY_CTRL_TMR2CMP_EN_MASK;
-
- ZLL->T2CMP = timeout;
- ZLL->IRQSTS = (ZLL->IRQSTS & ~ZLL_IRQSTS_TMR2MSK_MASK) |
- ZLL_IRQSTS_TMR2IRQ_MASK;
-
- ZLL->PHY_CTRL |= ZLL_PHY_CTRL_TMR2CMP_EN_MASK;
-}
-
-static inline void kw41z_tmr2_disable(void)
-{
- ZLL->IRQSTS |= ZLL_IRQSTS_TMR2MSK_MASK;
- ZLL->PHY_CTRL &= ~ZLL_PHY_CTRL_TMR2CMP_EN_MASK;
+ ZLL->IRQSTS = irqsts;
}
static enum ieee802154_hw_caps kw41z_get_capabilities(struct device *dev)
@@ -200,19 +306,16 @@
{
struct kw41z_context *kw41z = dev->driver_data;
- if (kw41z_prepare_for_new_state()) {
- SYS_LOG_DBG("Can't initiate new SEQ state");
- return -EBUSY;
- }
+ kw41z_phy_abort();
k_sem_init(&kw41z->seq_sync, 0, 1);
kw41z_enable_seq_irq();
ZLL->PHY_CTRL = (ZLL->PHY_CTRL & ~ZLL_PHY_CTRL_CCATYPE_MASK) |
ZLL_PHY_CTRL_CCATYPE(KW41Z_CCA_MODE1);
+
kw41z_set_seq_state(KW41Z_STATE_CCA);
- kw41z_tmr1_set_timeout(kw41z->rx_warmup_time + KW41Z_CCA_TIME);
k_sem_take(&kw41z->seq_sync, K_FOREVER);
return kw41z->seq_retval;
@@ -321,6 +424,9 @@
struct net_pkt *pkt = NULL;
struct net_buf *frag = NULL;
u8_t pkt_len, hw_lqi;
+ int rslt;
+
+ SYS_LOG_DBG("ENTRY: len: %d", len);
pkt_len = len - KW41Z_FCS_LENGTH;
@@ -339,7 +445,7 @@
net_pkt_frag_insert(pkt, frag);
#if CONFIG_SOC_MKW41Z4
- /* PKT_BUFFER_RX needs to be accessed alligned to 16 bits */
+ /* PKT_BUFFER_RX needs to be accessed aligned to 16 bits */
for (u16_t reg_val = 0, i = 0; i < pkt_len; i++) {
if (i % 2 == 0) {
reg_val = ZLL->PKT_BUFFER_RX[i/2];
@@ -349,7 +455,7 @@
}
}
#else /* CONFIG_SOC_MKW40Z4 */
- /* PKT_BUFFER needs to be accessed alligned to 32 bits */
+ /* PKT_BUFFER needs to be accessed aligned to 32 bits */
for (u32_t reg_val = 0, i = 0; i < pkt_len; i++) {
switch (i % 4) {
case 0:
@@ -380,8 +486,9 @@
net_pkt_set_ieee802154_lqi(pkt, kw41z_convert_lqi(hw_lqi));
/* ToDo: get the rssi as well and use net_pkt_set_ieee802154_rssi() */
- if (net_recv_data(kw41z->iface, pkt) < 0) {
- SYS_LOG_DBG("Packet dropped by NET stack");
+ rslt = net_recv_data(kw41z->iface, pkt);
+ if (rslt < 0) {
+ SYS_LOG_ERR("RCV Packet dropped by NET stack: %d", rslt);
goto out;
}
@@ -397,11 +504,17 @@
{
struct kw41z_context *kw41z = dev->driver_data;
u8_t payload_len = net_pkt_ll_reserve(pkt) + frag->len;
- u8_t *payload = frag->data - net_pkt_ll_reserve(pkt);
+#if KW41Z_AUTOACK_ENABLED
u32_t tx_timeout;
+#endif
- if (kw41z_prepare_for_new_state()) {
- SYS_LOG_DBG("Can't initiate new SEQ state");
+ /*
+ * The transmit requests are preceded by the CCA request. On
+ * completion of the CCA the sequencer should be in the IDLE
+ * state.
+ */
+ if (kw41z_get_seq_state() != KW41Z_STATE_IDLE) {
+ SYS_LOG_WRN("Can't initiate new SEQ state");
return -EBUSY;
}
@@ -412,10 +525,12 @@
#if CONFIG_SOC_MKW41Z4
((u8_t *)ZLL->PKT_BUFFER_TX)[0] = payload_len + KW41Z_FCS_LENGTH;
- memcpy(((u8_t *)ZLL->PKT_BUFFER_TX) + 1, payload, payload_len);
+ memcpy(((u8_t *)ZLL->PKT_BUFFER_TX) + 1,
+ (void *)(frag->data - net_pkt_ll_reserve(pkt)), payload_len);
#else /* CONFIG_SOC_MKW40Z4 */
((u8_t *)ZLL->PKT_BUFFER)[0] = payload_len + KW41Z_FCS_LENGTH;
- memcpy(((u8_t *)ZLL->PKT_BUFFER) + 1, payload, payload_len);
+ memcpy(((u8_t *)ZLL->PKT_BUFFER) + 1,
+ (void *)(frag->data - net_pkt_ll_reserve(pkt)), payload_len);
#endif
/* Set CCA mode */
@@ -425,25 +540,38 @@
/* Clear all IRQ flags */
ZLL->IRQSTS = ZLL->IRQSTS;
- tx_timeout = kw41z->tx_warmup_time + KW41Z_SHR_PHY_TIME +
- payload_len * KW41Z_PER_BYTE_TIME;
+ /*
+ * Current Zephyr 802.15.4 stack doesn't support ACK offload
+ */
+#if KW41Z_AUTOACK_ENABLED
/* Perform automatic reception of ACK frame, if required */
- if (KW41Z_AUTOACK_ENABLED) {
- tx_timeout += KW41Z_ACK_WAIT_TIME;
+ if (KW41Z_AUTOACK_ENABLED && payload->fc.ar) {
+ tx_timeout = kw41z->tx_warmup_time + KW41Z_SHR_PHY_TIME +
+ payload_len * KW41Z_PER_BYTE_TIME + 10 +
+ KW41Z_ACK_WAIT_TIME;
+
+ SYS_LOG_DBG("AUTOACK_ENABLED: len: %d, timeout: %d, seq: %d",
+ payload_len, tx_timeout, payload->sequence);
+
+ kw41z_tmr3_set_timeout(tx_timeout);
ZLL->PHY_CTRL |= ZLL_PHY_CTRL_RXACKRQD_MASK;
kw41z_set_seq_state(KW41Z_STATE_TXRX);
- kw41z_tmr2_set_timeout(tx_timeout);
- } else {
+ } else
+#endif
+ {
+ SYS_LOG_DBG("AUTOACK disabled: len: %d, seq: %d",
+ payload_len, payload->sequence);
+
ZLL->PHY_CTRL &= ~ZLL_PHY_CTRL_RXACKRQD_MASK;
kw41z_set_seq_state(KW41Z_STATE_TX);
- kw41z_tmr1_set_timeout(tx_timeout);
}
kw41z_enable_seq_irq();
k_sem_take(&kw41z->seq_sync, K_FOREVER);
+ SYS_LOG_DBG("seq_retval: %d", kw41z->seq_retval);
return kw41z->seq_retval;
}
@@ -452,103 +580,181 @@
u32_t irqsts = ZLL->IRQSTS;
u8_t state = kw41z_get_seq_state();
u8_t restart_rx = 1;
- u8_t rx_len;
+ u32_t rx_len;
+#if CONFIG_SYS_LOG_IEEE802154_DRIVER_LEVEL >= SYS_LOG_LEVEL_INFO
+ /*
+ * Variable is used in debug output to capture the state of the
+ * sequencer at interrupt.
+ */
+ u32_t seq_state = ZLL->SEQ_STATE;
+#endif
- /* TMR1 IRQ - time-out */
- if ((irqsts & ZLL_IRQSTS_TMR1IRQ_MASK) &&
- !(irqsts & ZLL_IRQSTS_TMR1MSK_MASK)) {
- SYS_LOG_DBG("TMR1 timeout");
- kw41z_tmr1_disable();
- kw41z_disable_seq_irq();
-
- if (state == KW41Z_STATE_CCA &&
- !(irqsts & ZLL_IRQSTS_CCA_MASK)) {
- kw41z_set_seq_state(KW41Z_STATE_IDLE);
- atomic_set(&kw41z_context_data.seq_retval, 0);
- restart_rx = 0;
- } else {
- atomic_set(&kw41z_context_data.seq_retval, -EBUSY);
- }
-
- k_sem_give(&kw41z_context_data.seq_sync);
- }
-
- /* TMR2 IRQ - time-out */
- if ((irqsts & ZLL_IRQSTS_TMR2IRQ_MASK) &&
- !(irqsts & ZLL_IRQSTS_TMR2MSK_MASK)) {
- SYS_LOG_DBG("TMR2 timeout");
- kw41z_tmr2_disable();
- atomic_set(&kw41z_context_data.seq_retval, -EBUSY);
- k_sem_give(&kw41z_context_data.seq_sync);
- }
-
- /* Sequence done IRQ */
- if ((state != KW41Z_STATE_IDLE) && (irqsts & ZLL_IRQSTS_SEQIRQ_MASK)) {
- kw41z_disable_seq_irq();
- kw41z_tmr1_disable();
- kw41z_set_seq_state(KW41Z_STATE_IDLE);
-
- switch (state) {
- case KW41Z_STATE_RX:
- SYS_LOG_DBG("RX seq done");
-
- /*
- * KW41Z seems to require some time before the RX SEQ
- * done IRQ is triggered and the data is actually
- * available in the packet buffer.
- */
- k_busy_wait(KW41Z_PRE_RX_WAIT_TIME);
-
- rx_len = (ZLL->IRQSTS &
- ZLL_IRQSTS_RX_FRAME_LENGTH_MASK) >>
- ZLL_IRQSTS_RX_FRAME_LENGTH_SHIFT;
- if (rx_len != 0) {
- kw41z_rx(&kw41z_context_data, rx_len);
- }
-
- break;
- case KW41Z_STATE_TXRX:
- SYS_LOG_DBG("TXRX seq done");
- kw41z_tmr2_disable();
- case KW41Z_STATE_TX:
- SYS_LOG_DBG("TX seq done");
- if (irqsts & ZLL_IRQSTS_CCA_MASK) {
- atomic_set(&kw41z_context_data.seq_retval,
- -EBUSY);
- } else {
- atomic_set(&kw41z_context_data.seq_retval, 0);
- }
-
- k_sem_give(&kw41z_context_data.seq_sync);
- break;
- case KW41Z_STATE_CCA:
- SYS_LOG_DBG("CCA seq done");
- if (irqsts & ZLL_IRQSTS_CCA_MASK) {
- atomic_set(&kw41z_context_data.seq_retval,
- -EBUSY);
- } else {
- atomic_set(&kw41z_context_data.seq_retval, 0);
- restart_rx = 0;
- }
-
- k_sem_give(&kw41z_context_data.seq_sync);
- break;
- default:
- break;
- }
- }
+ SYS_LOG_DBG("irqsts: 0x%08X, PHY_CTRL: 0x%08X, "
+ "SEQ_STATE: 0x%08X, state: %d",
+ irqsts, (unsigned int)ZLL->PHY_CTRL,
+ (unsigned int)seq_state, state);
/* Clear interrupts */
ZLL->IRQSTS = irqsts;
+ if ((!(ZLL->PHY_CTRL & ZLL_PHY_CTRL_RX_WMRK_MSK_MASK)) &&
+ (irqsts & ZLL_IRQSTS_RXWTRMRKIRQ_MASK)) {
+ /*
+ * There is a bug in the KW41Z where in noisy environments
+ * the RX sequence can get lost. The watermark mask IRQ can
+ * start TMR3 to complete the rest of the read or to assert
+ * IRQ if the sequencer gets lost so we can reset things.
+ * Note that a TX from the upper layers will also reset
+ * things so the problem is contained a bit in normal
+ * operation.
+ */
+ rx_len = (irqsts & ZLL_IRQSTS_RX_FRAME_LENGTH_MASK)
+ >> ZLL_IRQSTS_RX_FRAME_LENGTH_SHIFT;
+
+ SYS_LOG_DBG("WMRK irq: seq_state: 0x%08x, rx_len: %d",
+ seq_state, rx_len);
+
+ /*
+ * Assume the RX includes an auto-ACK so set the timer to
+ * include the RX frame size, crc, IFS, and ACK length and
+ * convert to symbols.
+ *
+ * IFS is 12 symbols
+ *
+ * ACK frame is 11 bytes: 4 preamble, 1 start of frame, 1 frame
+ * length, 2 frame control, 1 sequence, 2 FCS. Times two to
+ * convert to symbols.
+ */
+ rx_len = rx_len * 2 + 12 + 22 + 2;
+ kw41z_tmr3_set_timeout(rx_len);
+ restart_rx = 0;
+ }
+
+ /* Sequence done IRQ */
+ if ((state != KW41Z_STATE_IDLE) && (irqsts & ZLL_IRQSTS_SEQIRQ_MASK)) {
+ /*
+ * PLL unlock, the autosequence has been aborted due to
+ * PLL unlock
+ */
+ if (irqsts & ZLL_IRQSTS_PLL_UNLOCK_IRQ_MASK) {
+ SYS_LOG_ERR("PLL unlock error");
+ kw41z_isr_seq_cleanup();
+ restart_rx = 1;
+ }
+ /*
+ * TMR3 timeout, the autosequence has been aborted due to
+ * TMR3 timeout
+ */
+ else if ((irqsts & ZLL_IRQSTS_TMR3IRQ_MASK) &&
+ (!(irqsts & ZLL_IRQSTS_RXIRQ_MASK)) &&
+ (state != KW41Z_STATE_TX)) {
+
+ SYS_LOG_INF("a) TMR3 timeout: irqsts: 0x%08X, "
+ "seq_state: 0x%08X, state: %d",
+ irqsts, seq_state, state);
+
+ kw41z_isr_timeout_cleanup();
+ restart_rx = 1;
+ if (state == KW41Z_STATE_TXRX) {
+ /* TODO: What is the right error for no ACK? */
+ atomic_set(&kw41z_context_data.seq_retval,
+ -EBUSY);
+ }
+ } else {
+ kw41z_isr_seq_cleanup();
+
+ switch (state) {
+ case KW41Z_STATE_RX:
+ SYS_LOG_DBG("RX seq done: SEQ_STATE: 0x%08X",
+ (unsigned int)seq_state);
+
+ kw41z_tmr3_disable();
+
+ rx_len = (ZLL->IRQSTS &
+ ZLL_IRQSTS_RX_FRAME_LENGTH_MASK) >>
+ ZLL_IRQSTS_RX_FRAME_LENGTH_SHIFT;
+
+ if (irqsts & ZLL_IRQSTS_RXIRQ_MASK) {
+ if (rx_len != 0) {
+ kw41z_rx(&kw41z_context_data,
+ rx_len);
+ }
+ }
+ restart_rx = 1;
+ break;
+ case KW41Z_STATE_TXRX:
+ SYS_LOG_DBG("TXRX seq done");
+ kw41z_tmr3_disable();
+ case KW41Z_STATE_TX:
+ SYS_LOG_DBG("TX seq done");
+ if (irqsts & ZLL_IRQSTS_CCA_MASK) {
+ atomic_set(
+ &kw41z_context_data.seq_retval,
+ -EBUSY);
+ } else {
+ atomic_set(
+ &kw41z_context_data.seq_retval,
+ 0);
+ }
+
+ k_sem_give(&kw41z_context_data.seq_sync);
+ restart_rx = 1;
+
+ break;
+ case KW41Z_STATE_CCA:
+ SYS_LOG_DBG("CCA seq done");
+ if (irqsts & ZLL_IRQSTS_CCA_MASK) {
+ atomic_set(
+ &kw41z_context_data.seq_retval,
+ -EBUSY);
+ restart_rx = 1;
+ } else {
+ atomic_set(
+ &kw41z_context_data.seq_retval,
+ 0);
+ restart_rx = 0;
+ }
+
+ k_sem_give(&kw41z_context_data.seq_sync);
+ break;
+ default:
+ SYS_LOG_DBG("Unhandled state: %d", state);
+ restart_rx = 1;
+ break;
+ }
+ }
+ } else {
+ /* Timer 3 Compare Match */
+ if ((irqsts & ZLL_IRQSTS_TMR3IRQ_MASK) &&
+ (!(irqsts & ZLL_IRQSTS_TMR3MSK_MASK))) {
+
+ SYS_LOG_INF("b) TMR3 timeout: irqsts: 0x%08X, "
+ "seq_state: 0x%08X, state: %d",
+ irqsts, seq_state, state);
+
+ kw41z_tmr3_disable();
+ restart_rx = 0;
+ if (state != KW41Z_STATE_IDLE) {
+ kw41z_isr_timeout_cleanup();
+ restart_rx = 1;
+ /* If we are not running an automated
+ * sequence then handle event. TMR3 can expire
+ * during Recv/Ack sequence where the transmit
+ * of the ACK is not being interrupted.
+ */
+ }
+ }
+ }
+
/* Restart RX */
- if (restart_rx && state != KW41Z_STATE_IDLE) {
- kw41z_set_seq_state(KW41Z_STATE_IDLE);
- kw41z_wait_for_idle();
+ if (restart_rx) {
+ SYS_LOG_DBG("RESET RX");
kw41z_enable_seq_irq();
kw41z_set_seq_state(KW41Z_STATE_RX);
}
+ SYS_LOG_DBG("exit: IRQSTS: 0x%08X, PHY_CTRL: 0x%08X",
+ (unsigned int)ZLL->IRQSTS, (unsigned int)ZLL->PHY_CTRL);
}
static inline u8_t *get_mac(struct device *dev)
@@ -580,6 +786,7 @@
ZLL_PHY_CTRL_CRC_MSK_MASK |
ZLL_PHY_CTRL_PLL_UNLOCK_MSK_MASK |
ZLL_PHY_CTRL_FILTERFAIL_MSK_MASK |
+ ZLL_PHY_CTRL_RX_WMRK_MSK_MASK |
ZLL_PHY_CTRL_CCAMSK_MASK |
ZLL_PHY_CTRL_RXMSK_MASK |
ZLL_PHY_CTRL_TXMSK_MASK |
@@ -613,8 +820,7 @@
/* Set prescaller to obtain 1 symbol (16us) timebase */
ZLL->TMR_PRESCALE = 0x05;
- kw41z_tmr2_disable();
- kw41z_tmr1_disable();
+ kw41z_tmr3_disable();
/* Compute warmup times (scaled to 16us) */
kw41z->rx_warmup_time = (XCVR_TSM->END_OF_SEQ &
@@ -651,6 +857,12 @@
ZLL->CCA_LQI_CTRL &= ~ZLL_CCA_LQI_CTRL_LQI_OFFSET_COMP_MASK;
ZLL->CCA_LQI_CTRL |= ZLL_CCA_LQI_CTRL_LQI_OFFSET_COMP(96);
+ /* Enable the RxWatermark IRQ */
+ ZLL->PHY_CTRL &= ~(ZLL_PHY_CTRL_RX_WMRK_MSK_MASK);
+ /* Set Rx watermark level */
+ ZLL->RX_WTR_MARK = 0;
+
+
/* Set default channel to 2405 MHZ */
kw41z_set_channel(dev, KW41Z_DEFAULT_CHANNEL);
@@ -689,9 +901,14 @@
.tx = kw41z_tx,
};
-NET_DEVICE_INIT(kw41z, CONFIG_IEEE802154_KW41Z_DRV_NAME,
- kw41z_init, &kw41z_context_data, NULL,
- CONFIG_IEEE802154_KW41Z_INIT_PRIO,
- &kw41z_radio_api, IEEE802154_L2,
- NET_L2_GET_CTX_TYPE(IEEE802154_L2),
- KW41Z_PSDU_LENGTH);
+NET_DEVICE_INIT(
+ kw41z, /* Device Name */
+ CONFIG_IEEE802154_KW41Z_DRV_NAME, /* Driver Name */
+ kw41z_init, /* Initialization Function */
+ &kw41z_context_data, /* Context data */
+ NULL, /* Configuration info */
+ CONFIG_IEEE802154_KW41Z_INIT_PRIO, /* Initial priority */
+ &kw41z_radio_api, /* API interface functions */
+ IEEE802154_L2, /* L2 */
+ NET_L2_GET_CTX_TYPE(IEEE802154_L2), /* L2 context type */
+ KW41Z_PSDU_LENGTH); /* MTU size */
diff --git a/samples/net/echo_client/prj_frdm_kw41z.conf b/samples/net/echo_client/prj_frdm_kw41z.conf
new file mode 100644
index 0000000..68c6726
--- /dev/null
+++ b/samples/net/echo_client/prj_frdm_kw41z.conf
@@ -0,0 +1,73 @@
+CONFIG_UART_CONSOLE=y
+CONFIG_RTT_CONSOLE=n
+CONFIG_HAS_SEGGER_RTT=n
+#CONFIG_OPENOCD_SUPPORT=y
+
+CONFIG_BOOT_BANNER=y
+
+CONFIG_STACK_SENTINEL=y
+CONFIG_THREAD_MONITOR=y
+CONFIG_OBJECT_TRACING=y
+CONFIG_KERNEL_SHELL=y
+
+CONFIG_MAIN_STACK_SIZE=2048
+CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2048
+
+CONFIG_NETWORKING=y
+
+CONFIG_NET_DEBUG_NET_PKT=y
+
+CONFIG_NET_BUF_RX_COUNT=96
+CONFIG_NET_BUF_TX_COUNT=64
+
+CONFIG_NET_IPV4=n
+CONFIG_NET_IPV6=y
+CONFIG_NET_IPV6_RA_RDNSS=y
+CONFIG_NET_IF_UNICAST_IPV6_ADDR_COUNT=2
+
+CONFIG_NET_6LO=y
+CONFIG_NET_DEBUG_6LO=y
+
+CONFIG_NET_BUF_LOG=y
+CONFIG_SYS_LOG_NET_BUF_LEVEL=3
+
+CONFIG_NET_LOG=y
+CONFIG_SYS_LOG_NET_LEVEL=2
+
+CONFIG_SYS_LOG_SHOW_COLOR=y
+CONFIG_INIT_STACKS=y
+CONFIG_PRINTK=y
+
+CONFIG_NET_DEBUG_CORE=y
+CONFIG_NET_DEBUG_IPV6_NBR_CACHE=y
+CONFIG_NET_DEBUG_IPV6=y
+CONFIG_NET_DEBUG_CONTEXT=y
+CONFIG_NET_DEBUG_NET_PKT=y
+CONFIG_NET_DEBUG_UTILS=y
+CONFIG_NET_DEBUG_IF=y
+CONFIG_NET_DEBUG_ICMPV6=y
+CONFIG_NET_DEBUG_CONN=y
+CONFIG_NET_STATISTICS=y
+CONFIG_NET_STATISTICS_PERIODIC_OUTPUT=y
+
+CONFIG_NET_L2_IEEE802154=y
+CONFIG_NET_DEBUG_L2_IEEE802154=y
+CONFIG_NET_L2_IEEE802154_FRAGMENT=y
+CONFIG_NET_DEBUG_L2_IEEE802154_FRAGMENT=y
+CONFIG_NET_L2_IEEE802154_FRAGMENT_REASS_CACHE_SIZE=4
+
+CONFIG_NET_APP_IEEE802154_PAN_ID=0xbeef
+
+
+CONFIG_NET_L2_IEEE802154_SECURITY=n
+CONFIG_NET_L2_IEEE802154_SHELL=y
+
+CONFIG_IEEE802154_KW41Z=y
+CONFIG_SYS_LOG_IEEE802154_DRIVER_LEVEL=3
+
+
+CONFIG_NET_APP_CLIENT=y
+CONFIG_NET_APP_SETTINGS=y
+CONFIG_NET_APP_MY_IPV6_ADDR="2001:db8::1"
+CONFIG_NET_APP_PEER_IPV6_ADDR="2001:db8::2"
+CONFIG_NET_APP_IEEE802154_DEV_NAME="KW41Z"
diff --git a/samples/net/echo_server/prj_frdm_kw41z.conf b/samples/net/echo_server/prj_frdm_kw41z.conf
new file mode 100644
index 0000000..4b98107
--- /dev/null
+++ b/samples/net/echo_server/prj_frdm_kw41z.conf
@@ -0,0 +1,65 @@
+CONFIG_UART_CONSOLE=y
+CONFIG_RTT_CONSOLE=n
+CONFIG_HAS_SEGGER_RTT=n
+CONFIG_BOOT_BANNER=y
+
+CONFIG_STACK_SENTINEL=y
+CONFIG_THREAD_MONITOR=y
+CONFIG_OBJECT_TRACING=y
+CONFIG_KERNEL_SHELL=y
+
+
+CONFIG_NETWORKING=y
+
+CONFIG_NET_BUF_RX_COUNT=80
+CONFIG_NET_BUF_TX_COUNT=40
+
+CONFIG_NET_IPV4=n
+CONFIG_NET_IPV6=y
+CONFIG_NET_IPV6_RA_RDNSS=y
+CONFIG_NET_IF_UNICAST_IPV6_ADDR_COUNT=2
+
+CONFIG_NET_6LO=y
+CONFIG_NET_DEBUG_6LO=y
+
+CONFIG_NET_BUF_LOG=y
+CONFIG_SYS_LOG_NET_BUF_LEVEL=3
+
+CONFIG_NET_LOG=y
+CONFIG_SYS_LOG_NET_LEVEL=2
+
+CONFIG_SYS_LOG_SHOW_COLOR=y
+CONFIG_INIT_STACKS=y
+CONFIG_PRINTK=y
+
+CONFIG_NET_DEBUG_CORE=y
+CONFIG_NET_DEBUG_IPV6_NBR_CACHE=y
+CONFIG_NET_DEBUG_IPV6=y
+CONFIG_NET_DEBUG_CONTEXT=y
+CONFIG_NET_DEBUG_NET_PKT=y
+CONFIG_NET_DEBUG_UTILS=y
+CONFIG_NET_DEBUG_IF=y
+CONFIG_NET_DEBUG_ICMPV6=y
+CONFIG_NET_DEBUG_CONN=y
+CONFIG_NET_STATISTICS=y
+CONFIG_NET_STATISTICS_PERIODIC_OUTPUT=y
+
+CONFIG_NET_L2_IEEE802154=y
+CONFIG_NET_DEBUG_L2_IEEE802154=y
+CONFIG_NET_L2_IEEE802154_FRAGMENT=y
+CONFIG_NET_DEBUG_L2_IEEE802154_FRAGMENT=y
+CONFIG_NET_L2_IEEE802154_FRAGMENT_REASS_CACHE_SIZE=2
+
+CONFIG_NET_APP_IEEE802154_PAN_ID=0xbeef
+CONFIG_NET_L2_IEEE802154_SECURITY=n
+CONFIG_NET_L2_IEEE802154_SHELL=y
+
+CONFIG_IEEE802154_KW41Z=y
+CONFIG_SYS_LOG_IEEE802154_DRIVER_LEVEL=3
+
+
+CONFIG_NET_APP_SERVER=y
+CONFIG_NET_APP_SETTINGS=y
+CONFIG_NET_APP_MY_IPV6_ADDR="2001:db8::2"
+CONFIG_NET_APP_PEER_IPV6_ADDR="2001:db8::1"
+CONFIG_NET_APP_IEEE802154_DEV_NAME="KW41Z"