Spirit Network Driver: Add support for watermark interrupts on RX FIFO. Reduce max packet length to avoid an errata.
This commit is contained in:
parent
3b1e2ac4fd
commit
84001f79a0
@ -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.
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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"
|
||||
|
@ -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)
|
||||
|
@ -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.
|
||||
|
Loading…
Reference in New Issue
Block a user