Spirit Network Driver: Add support for watermark interrupts on RX FIFO. Reduce max packet length to avoid an errata.

This commit is contained in:
Gregory Nutt 2017-08-06 10:10:55 -06:00
parent 3b1e2ac4fd
commit 84001f79a0
6 changed files with 201 additions and 40 deletions

View File

@ -504,3 +504,17 @@ Configuration sub-directories
interactions by the LP and HP work queue. I restructured the tasking to
reduce the amount of interlocking, but this did not eliminate the RX FIFO
errors.
Hmmm.. Appears to be a chip Errata: "Sometimes Spirit1 seems to NOT
deliver (correctly) the 'IRQ_RX_DATA_READY' event for packets which
have a length which is close to a multiple of RX FIFO size. Furthermore,
in these cases also the content delivery seems to be compromised as well
as the generation of RX/TX FIFO errors. This can be avoided by reducing
the maximum packet length to a value which is lower than the RX FIFO
size."
I tried implementing the RX FIFO almost full water mark thinking this
might be a work around... it is not. Still RX FIFO errors. From my
reading, the only known work-around is to reduce the maximum packet
size so that it is smaller than 96.

View File

@ -19,14 +19,14 @@ CONFIG_FS_PROCFS=y
CONFIG_HAVE_CXX=y
CONFIG_HAVE_CXXINITIALIZE=y
CONFIG_INTELHEX_BINARY=y
CONFIG_IOB_BUFSIZE=96
CONFIG_IOB_BUFSIZE=84
CONFIG_IOB_NBUFFERS=32
CONFIG_IOB_NCHAINS=16
CONFIG_LIBM=y
CONFIG_MAX_TASKS=16
CONFIG_MAX_WDOGPARMS=2
CONFIG_MM_REGIONS=2
CONFIG_NET_6LOWPAN_FRAMELEN=96
CONFIG_NET_6LOWPAN_FRAMELEN=84
CONFIG_NET_6LOWPAN=y
CONFIG_NET_BROADCAST=y
CONFIG_NET_HOSTNAME="B-L475E-IOT01A"
@ -75,6 +75,7 @@ CONFIG_SPIRIT_BROADCAST=y
CONFIG_SPIRIT_CRCDISABLE=y
CONFIG_SPIRIT_MULTICAST=y
CONFIG_SPIRIT_NETDEV=y
CONFIG_SPIRIT_PKTLEN=84
CONFIG_START_DAY=2
CONFIG_START_MONTH=8
CONFIG_STM32L4_SPI3=y

View File

@ -36,14 +36,14 @@ CONFIG_FS_PROCFS=y
CONFIG_HAVE_CXX=y
CONFIG_HAVE_CXXINITIALIZE=y
CONFIG_INTELHEX_BINARY=y
CONFIG_IOB_BUFSIZE=96
CONFIG_IOB_BUFSIZE=84
CONFIG_IOB_NBUFFERS=32
CONFIG_IOB_NCHAINS=16
CONFIG_LIBM=y
CONFIG_MAX_TASKS=16
CONFIG_MAX_WDOGPARMS=2
CONFIG_MM_REGIONS=2
CONFIG_NET_6LOWPAN_FRAMELEN=96
CONFIG_NET_6LOWPAN_FRAMELEN=84
CONFIG_NET_6LOWPAN=y
CONFIG_NET_BROADCAST=y
CONFIG_NET_HOSTNAME="B-L475E-IOT01A"
@ -91,6 +91,7 @@ CONFIG_SPIRIT_BROADCAST=y
CONFIG_SPIRIT_CRCDISABLE=y
CONFIG_SPIRIT_MULTICAST=y
CONFIG_SPIRIT_NETDEV=y
CONFIG_SPIRIT_PKTLEN=84
CONFIG_START_DAY=2
CONFIG_START_MONTH=8
CONFIG_STM32L4_SPI3=y

View File

@ -24,6 +24,13 @@ config SPIRIT_PKTLEN
Fixed pkt sizes are used. This setting describes that fixed packet
size.
"Sometimes Spirit1 seems to NOT deliver (correctly) the 'IRQ_RX_DATA_READY'
event for packets which have a length which is close to a multiple of
RX FIFO size. Furthermore, in these cases also the content delivery seems
to be compromised as well as the generation of RX/TX FIFO errors.
This can be avoided by reducing the maximum packet length to a value which
is lower than the RX FIFO size."
config SPIRIT_FIFOS
bool "FIFO Watermarks"
default n
@ -32,21 +39,22 @@ config SPIRIT_FIFOS
The Spirit hardware can provided interrupts when indicate when the
RX or TX FIFOs are almost full or empty. This is useful for
supporting very large packets, larger than the FIFO size. The RX/TX
FIFO size is 96 bytes. As long as the packet size is less then or
equal 96 bytes, this feature is not needed.
FIFO size is 96 bytes. If the packet size is significantly less than
96 bytes, this feature is not needed. It is required for packet sizes
greater than 96 bytes and if it is not selected, there may be
occurrences of RX FIFO errors if the packet size is less than but close
to 96.
NOTE: Marked experimental because this feature is not yet implement
(hooks are present). You should not enable this feature unless you
plan to implement the feature.
"Sometimes Spirit1 seems to NOT deliver (correctly) the 'IRQ_RX_DATA_READY'
event for packets which have a length which is close to a multiple of
RX FIFO size. Furthermore, in these cases also the content delivery seems
to be compromised as well as the generation of RX/TX FIFO errors.
This can be avoided by reducing the maximum packet length to a value which
is lower than the RX FIFO size."
config SPIRIT_PKTLEN
int "Fixed packet length"
default 96
range 1 96 if !SPIRIT_FIFOS
range 1 65535 if SPIRIT_FIFOS
---help---
Fixed pkt sizes are used. This setting describes that fixed packet
size.
From my reading, the only known work-around is to reduce the maximum
packet size so that it is smaller than 96. Hence, this option is
conditioned on EXPERMENTAL.
config SPIRIT_PROMISICUOUS
bool "Promiscuous mode"

View File

@ -223,6 +223,11 @@
# define SPIRIT_NODE_ADDR 0x34
#endif
/* Linear FIFO thresholds */
#define SPIRIT_RXFIFO_ALMOSTFULL (3 * SPIRIT_MAX_FIFO_LEN / 4)
#define SPIRIT_TXFIFO_ALMOSTEMPTY (1 * SPIRIT_MAX_FIFO_LEN / 4)
/* TX poll delay = 1 seconds. CLK_TCK is the number of clock ticks per second */
#define SPIRIT_WDDELAY (1*CLK_TCK)
@ -261,6 +266,9 @@ struct spirit_driver_s
FAR struct pktradio_metadata_s *txtail; /* Tail of pending TX transfers */
FAR struct pktradio_metadata_s *rxhead; /* Head of completed RX transfers */
FAR struct pktradio_metadata_s *rxtail; /* Tail of completed RX transfers */
#ifdef CONFIG_SPIRIT_FIFOS
FAR struct iob_s *rxbuffer; /* Receiving into this buffer */
#endif
struct work_s irqwork; /* Interrupt continuation work (HP) */
struct work_s txwork; /* TX work queue support (HP) */
struct work_s rxwork; /* RX work queue support (LP) */
@ -1030,8 +1038,19 @@ static void spirit_interrupt_work(FAR void *arg)
/* Discard RX data */
DEBUGVERIFY(spirit_command(spirit, CMD_FLUSHRXFIFO));
irqstatus.IRQ_RX_DATA_READY = 0;
irqstatus.IRQ_VALID_SYNC = 0;
irqstatus.IRQ_RX_DATA_READY = 0;
irqstatus.IRQ_VALID_SYNC = 0;
#ifdef CONFIG_SPIRIT_FIFOS
irqstatus.IRQ_RX_FIFO_ALMOST_FULL = 0;
/* Discard any RX buffer that might have been allocated */
if (priv->rxbuffer != NULL)
{
iob_free(priv->rxbuffer);
priv->rxbuffer = NULL;
}
#endif
/* Revert the receiving state */
@ -1106,7 +1125,7 @@ static void spirit_interrupt_work(FAR void *arg)
spirit_schedule_transmit_work(priv);
}
#ifdef CONFIG_SPIRIT_FIFOS
#if defined(CONFIG_SPIRIT_FIFOS) && CONFIG_SPIRIT_PKTLEN > SPIRIT_MAX_FIFO_LEN
/* The IRQ_TX_FIFO_ALMOST_EMPTY notifies an nearly empty TX fifo.
* Necessary for sending large packets > sizeof(TX FIFO).
*/
@ -1133,6 +1152,23 @@ static void spirit_interrupt_work(FAR void *arg)
DEBUGASSERT(priv->state == DRIVER_STATE_IDLE);
priv->state = DRIVER_STATE_RECEIVING;
}
#ifdef CONFIG_SPIRIT_FIFOS
/* Pre-allocate an IOB to hold the received data */
if (priv->rxbuffer == NULL)
{
priv->rxbuffer = iob_alloc(0);
}
if (priv->rxbuffer != NULL)
{
priv->rxbuffer->io_len = 0;
priv->rxbuffer->io_offset = 0;
priv->rxbuffer->io_pktlen = 0;
priv->rxbuffer->io_flink = NULL;
}
#endif
}
/* The IRQ_RX_DATA_READY notifies that a new packet has been received */
@ -1141,15 +1177,42 @@ static void spirit_interrupt_work(FAR void *arg)
{
FAR struct pktradio_metadata_s *pktmeta;
FAR struct iob_s *iob;
uint8_t offset;
uint8_t count;
wlinfo("Data ready\n");
NETDEV_RXPACKETS(&priv->radio.r_dev);
/* Check the packet size */
#ifdef CONFIG_SPIRIT_FIFOS
/* Do not process RX FIFO almost full interrupt */
irqstatus.IRQ_RX_FIFO_ALMOST_FULL = 0;
/* There should be a RX buffer that was allocated when the data sync
* interrupt was processed.
*/
iob = priv->rxbuffer;
priv->rxbuffer = NULL;
/* Get the offset to the data from the last RX FIFO almost full
* interrupt.
*/
offset = 0;
if (iob != NULL)
{
offset = iob->io_len;
}
#else
offset = 0;
#endif
/* Get the number of bytes avaialable in the RX FIFO */
count = spirit_fifo_get_rxcount(spirit);
if (count > CONFIG_IOB_BUFSIZE)
wlinfo("Receiving %u bytes (%u total)\n", count, count + offset);
if ((offset + count) > CONFIG_IOB_BUFSIZE)
{
wlwarn("WARNING: Packet too large... dropping\n");
DEBUGVERIFY(spirit_command(spirit, CMD_FLUSHRXFIFO));
@ -1158,14 +1221,15 @@ static void spirit_interrupt_work(FAR void *arg)
}
else
{
wlinfo("Receiving %u bytes\n", count);
#ifdef CONFIG_SPIRIT_FIFOS
if (iob == NULL)
#endif
{
/* Allocate an I/O buffer to hold the received packet. */
/* Allocate an I/O buffer to hold the received packet.
* REVISIT: Not a good place to wait. Perhaps we should pre-
* allocate a few I/O buffers?
*/
iob = iob_alloc(0);
}
iob = iob_alloc(0);
if (iob == NULL)
{
wlerr("ERROR: Failed to allocate IOB... dropping\n");
@ -1180,9 +1244,9 @@ static void spirit_interrupt_work(FAR void *arg)
}
else
{
/* Read the packet into the I/O buffer */
/* Read the remainder of the packet into the I/O buffer */
DEBUGVERIFY(spirit_fifo_read(spirit, iob->io_data, count));
DEBUGVERIFY(spirit_fifo_read(spirit, &iob->io_data[offset], count));
iob->io_len = spirit_pktstack_get_rxpktlen(spirit);
iob->io_offset = 0;
iob->io_pktlen = iob->io_len;
@ -1262,8 +1326,58 @@ static void spirit_interrupt_work(FAR void *arg)
if (irqstatus.IRQ_RX_FIFO_ALMOST_FULL != 0)
{
FAR struct iob_s *iob;
uint8_t offset;
uint8_t count;
wlinfo("RX FIFO almost full\n");
#warning Missing logic
/* There should be a RX buffer that was allocated when the data sync
* interrupt was processed.
*/
if (priv->rxbuffer != NULL)
{
iob = priv->rxbuffer;
offset = iob->io_len;
}
else
{
/* If not, then allocate one now. */
priv->rxbuffer = iob_alloc(0);
iob = priv->rxbuffer;
offset = 0;
}
if (iob != NULL)
{
/* Get the number of bytes avaialable in the RX FIFO */
count = spirit_fifo_get_rxcount(spirit);
wlinfo("Receiving %u bytes (%u so far)\n", count, count + offset);
if ((offset + count) > CONFIG_IOB_BUFSIZE)
{
wlwarn("WARNING: Packet too large... dropping\n");
DEBUGVERIFY(spirit_command(spirit, CMD_FLUSHRXFIFO));
priv->state = DRIVER_STATE_IDLE;
NETDEV_RXDROPPED(&priv->radio.r_dev);
priv->rxbuffer = NULL;
iob_free(iob);
}
else
{
/* Read more of the packet into the I/O buffer */
DEBUGVERIFY(spirit_fifo_read(spirit, &iob->io_data[offset], count));
iob->io_len = count + offset;
iob->io_offset = 0;
iob->io_pktlen = iob->io_len;
iob->io_flink = NULL;
}
}
}
#endif
@ -2215,6 +2329,27 @@ int spirit_hw_initialize(FAR struct spirit_driver_s *priv,
return ret;
}
#ifdef CONFIG_SPIRIT_FIFOS
/* Configure the linear FIFOs */
wlinfo("Configure linear FIFOs\n");
ret = spirit_fifo_set_rxalmostfull(spirit, SPIRIT_RXFIFO_ALMOSTFULL);
if (ret < 0)
{
wlerr("ERROR: spirit_fifo_set_rxalmostfull failed: %d\n", ret);
return ret;
}
#if CONFIG_SPIRIT_PKTLEN > SPIRIT_MAX_FIFO_LEN
ret = spirit_fifo_set_txalmostempty(spirit, SPIRIT_TXFIFO_ALMOSTEMPTY);
if (ret < 0)
{
wlerr("ERROR: spirit_fifo_set_txalmostempty failed: %d\n", ret);
return ret;
}
#endif
#endif
/* Enable the following interrupt sources, routed to GPIO */
wlinfo("Configure Interrupts\n");
@ -2282,12 +2417,14 @@ int spirit_hw_initialize(FAR struct spirit_driver_s *priv,
}
#ifdef CONFIG_SPIRIT_FIFOS
#if CONFIG_SPIRIT_PKTLEN > SPIRIT_MAX_FIFO_LEN
ret = spirit_irq_enable(spirit, TX_FIFO_ALMOST_EMPTY, S_ENABLE);
if (ret < 0)
{
wlerr("ERROR: Enable TX_FIFO_ALMOST_EMPTY failed: %d\n", ret);
return ret;
}
#endif
ret = spirit_irq_enable(spirit, RX_FIFO_ALMOST_FULL, S_ENABLE);
if (ret < 0)

View File

@ -97,7 +97,7 @@ uint8_t spirit_fifo_get_txcount(FAR struct spirit_library_s *spirit);
* Name: spirit_fifo_set_rxalmostfull
*
* Description:
* Sets the almost full threshold for the Rx FIFO. When the number of
* Sets the almost full threshold for the Rx FIFO. When the number of
* elements in RX FIFO reaches this value an interrupt can be generated to
* the MCU.
*
@ -106,8 +106,8 @@ uint8_t spirit_fifo_get_txcount(FAR struct spirit_library_s *spirit);
* when the number of elements is equals to 96-7 = 89.
*
* Input Parameters:
* spirit - Reference to a Spirit library state structure instance
* threshold almost full threshold.
* spirit - Reference to a Spirit library state structure instance
* threshold - Almost full threshold.
*
* Returned Value:
* Zero (OK) on success; a negated errno value on failure.
@ -146,8 +146,8 @@ uint8_t spirit_fifo_get_rxalmostfull(FAR struct spirit_library_s *spirit);
* the MCU.
*
* Input Parameters:
* spirit - Reference to a Spirit library state structure instance
* threshold almost empty threshold.
* spirit - Reference to a Spirit library state structure instance
* threshold - Almost empty threshold.
*
* Returned Value:
* Zero (OK) on success; a negated errno value on failure.
@ -186,8 +186,8 @@ uint8_t spirit_fifo_get_rxalmostempty(FAR struct spirit_library_s *spirit);
* when the number of elements is equals to 96-7 = 89.
*
* Input Parameters:
* spirit - Reference to a Spirit library state structure instance
* threshold almost full threshold.
* spirit - Reference to a Spirit library state structure instance
* threshold - Almost full threshold.
*
* Returned Value:
* Zero (OK) on success; a negated errno value on failure.
@ -226,8 +226,8 @@ uint8_t spirit_fifo_get_txalmostfull(FAR struct spirit_library_s *spirit);
* to the MCU.
*
* Input Parameters:
* spirit - Reference to a Spirit library state structure instance
* threshold: almost empty threshold.
* spirit - Reference to a Spirit library state structure instance
* threshold - Almost empty threshold.
*
* Returned Value:
* Zero (OK) on success; a negated errno value on failure.