diff --git a/Documentation/NuttShell.html b/Documentation/NuttShell.html
index c23950484cd..6095357a5ce 100644
--- a/Documentation/NuttShell.html
+++ b/Documentation/NuttShell.html
@@ -8,7 +8,7 @@
kill |
!CONFIG_DISABLE_SIGNALS |
@@ -5486,10 +5524,10 @@ xxd -i romfs_img >nsh_romfsimg.h
CONFIG_NSH_ROMFSMOUNTPT
CONFIG_NSH_ROMFSSECTSIZE
CONFIG_NSH_STRERROR
+ CONFIG_NSH_TELNET
|
- - NSH library (
nshlib)
- NSH library (
nshlib)
nsh_consolemain()
nsh_initialize()
diff --git a/arch/arm/src/lpc54xx/Kconfig b/arch/arm/src/lpc54xx/Kconfig
index bc77fb07199..947350c7733 100644
--- a/arch/arm/src/lpc54xx/Kconfig
+++ b/arch/arm/src/lpc54xx/Kconfig
@@ -667,6 +667,24 @@ endif # LPC54_EMC_DYNAMIC
endmenu # EMC Configuration
+menu "SPI Master configuration"
+ depends on LPC54_HAVE_SPI_MASTER
+
+config LPC54_SPI_WIDEDATA
+ bool "Enable wide data"
+ default n
+ ---help---
+ The LPC54xxx SPI supports data widths from 4 through 16 bits. For
+ data from 4 through 8 bits; the receive and transmit data is
+ represented with a uint8_t type. For the wider data, data is
+ represented with a uint16_t. There is duplication of logic for this
+ different widths. By default, SPI wide data is disabled since that
+ is the less frequently used data type and disabling wide data can
+ result in some size reduction. Select this option if you need wide
+ SPI data.
+
+endmenu # SPI Master configuration
+
menu "Ethernet configuration"
depends on LPC54_ETHERNET
diff --git a/arch/arm/src/lpc54xx/chip/lpc54_spi.h b/arch/arm/src/lpc54xx/chip/lpc54_spi.h
index 9ab286e18a9..21071fbb371 100644
--- a/arch/arm/src/lpc54xx/chip/lpc54_spi.h
+++ b/arch/arm/src/lpc54xx/chip/lpc54_spi.h
@@ -260,38 +260,146 @@
/* Register bit definitions *************************************************************************/
/* SPI Configuration register */
-#define SPI_CFG_
+
+#define SPI_CFG_ENABLE (1 << 0) /* Bit 0: SPI enable */
+#define SPI_CFG_MASTER (1 << 2) /* Bit 2: Master mode select */
+#define SPI_CFG_LSBF (1 << 3) /* Bit 3: LSB First mode enable */
+#define SPI_CFG_CPHA (1 << 4) /* Bit 4: Clock Phase select */
+#define SPI_CFG_CPOL (1 << 5) /* Bit 5: Clock Polarity select */
+#define SPI_CFG_LOOP (1 << 7) /* Bit 7: Loopback mode enable */
+#define SPI_CFG_SPOL0 (1 << 8) /* Bit 8: SSEL0 Polarity select */
+#define SPI_CFG_SPOL1 (1 << 9) /* Bit 9: SSEL1 Polarity select */
+#define SPI_CFG_SPOL2 (1 << 10) /* Bit 10: SSEL2 Polarity select */
+#define SPI_CFG_SPOL3 (1 << 11) /* Bit 11: SSEL3 Polarity select */
+
/* SPI Delay register */
-#define SPI_DLY_
+
+#define SPI_DLY_PRE_DELAY_SHIFT (0) /* Bits 0-3: Time between SSEL assertion and data transfer */
+#define SPI_DLY_PRE_DELAY_MASK (15 << SPI_DLY_PRE_DELAY_SHIFT)
+# define SPI_DLY_PRE_DELAY(n) ((uint32_t)(n) << SPI_DLY_PRE_DELAY_SHIFT)
+#define SPI_DLY_POST_DELAY_SHIFT (4) /* Bits 4-7: Time between tdata transfer and SSEL deassertion */
+#define SPI_DLY_POST_DELAY_MASK (15 << SPI_DLY_POST_DELAY_SHIFT)
+# define SPI_DLY_POST_DELAY(n) ((uint32_t)(n) << SPI_DLY_POST_DELAY_SHIFT)
+#define SPI_DLY_FRAME_DELAY_SHIFT (8) /* Bits 8-11: Minimum amount of time between frames */
+#define SPI_DLY_FRAME_DELAY_MASK (15 << SPI_DLY_FRAME_DELAY_SHIFT)
+# define SPI_DLY_FRAME_DELAY(n) ((uint32_t)(n) << SPI_DLY_FRAME_DELAY_SHIFT)
+#define SPI_DLY_TRANSFER_DELAY_SHIFT (12) /* Bits 12-15: Time SSEL deasserted between transfers */
+#define SPI_DLY_TRANSFER_DELAY_MASK (15 << SPI_DLY_TRANSFER_DELAY_SHIFT)
+# define SPI_DLY_TRANSFER_DELAY(n) ((uint32_t)(n) << SPI_DLY_TRANSFER_DELAY_SHIFT)
+
/* SPI Status register */
-#define SPI_STAT_
-/* SPI Interrupt Enable read and set */
-#define SPI_INTENSET_
-/* SPI Interrupt Enable Clear */
-#define SPI_INTENCLR_
+
+#define SPI_STAT_SSA (1 << 4) /* Bit 4: Slave Select Assert */
+#define SPI_STAT_SSD (1 << 5) /* Bit 5: Slave Select Deassert */
+#define SPI_STAT_STALLED (1 << 6) /* Bit 6: Stalled status flag */
+#define SPI_STAT_ENDTRANSFER (1 << 7) /* Bit 7: End Transfer control bit */
+#define SPI_STAT_MSTIDLE (1 << 8) /* Bit 8: Master idle status flag */
+
+/* SPI Interrupt Enable read and set, SPI Interrupt Enable Clear, and SPI Interrupt Status */
+
+#define SPI_INT_SSA (1 << 4) /* Bit 4: Slave select assert interrupt */
+#define SPI_INT_SSD (1 << 5) /* Bit 5: Slave select deassert interrupt */
+#define SPI_INT_MSTIDLE (1 << 8) /* Bit 8: Master idle interrupt */
+
/* SPI clock Divider */
-#define SPI_DIV_
-/* SPI Interrupt Status */
-#define SPI_INTSTAT_
+
+#define SPI_DIV_SHIFT (0) /* Bits 0-15: Rate divider value */
+#define SPI_DIV_MASK (0xffff << SPI_DIV_SHIFT)
+# define SPI_DIV(n) ((uint32_t)((n)-1) << SPI_DIV_SHIFT)
+
/* FIFO configuration and enable register */
-#define SPI_FIFOCFG_
+
+#define SPI_FIFOCFG_ENABLETX (1 << 0) /* Bit 0: Enable the transmit FIFO) */
+#define SPI_FIFOCFG_ENABLERX (1 << 1) /* Bit 1: Enable the receive FIFO) */
+#define SPI_FIFOCFG_SIZE_SHIFT (4) /* Bits 4-5: FIFO size configuration (read-only) */
+#define SPI_FIFOCFG_SIZE_MASK (3 << SPI_FIFOCFG_SIZE_SHIFT)
+# define SPI_FIFOCFG_SIZE_8x16 (1 << SPI_FIFOCFG_SIZE_SHIFT) /* FIFO is configured as 8 entries of 16 bits */
+#define SPI_FIFOCFG_DMATX (1 << 12) /* Bit 12: DMA configuration for transmit */
+#define SPI_FIFOCFG_DMARX (1 << 13) /* Bit 13: DMA configuration for receive */
+#define SPI_FIFOCFG_WAKETX (1 << 14) /* Bit 14: Wake-up for transmit FIFO level */
+#define SPI_FIFOCFG_WAKERX (1 << 15) /* Bit 15: Wake-up for receive FIFO level */
+#define SPI_FIFOCFG_EMPTYTX (1 << 16) /* Bit 16: Empty command for the transmit FIFO) */
+#define SPI_FIFOCFG_EMPTYRX (1 << 17) /* Bit 17: Empty command for the receive FIFO) */
+
/* FIFO status register */
-#define SPI_FIFOSTAT_
+
+#define SPI_FIFOSTAT_TXERR (1 << 0) /* Bit 0: TX FIFO error */
+#define SPI_FIFOSTAT_RXERR (1 << 1) /* Bit 1: RX FIFO error */
+#define SPI_FIFOSTAT_PERINT (1 << 3) /* Bit 3: Peripheral interrupt */
+#define SPI_FIFOSTAT_TXEMPTY (1 << 4) /* Bit 4: Transmit FIFO empty */
+#define SPI_FIFOSTAT_TXNOTFULL (1 << 5) /* Bit 5: Transmit FIFO not full */
+#define SPI_FIFOSTAT_RXNOTEMPTY (1 << 6) /* Bit 6: Receive FIFO not empty */
+#define SPI_FIFOSTAT_RXFULL (1 << 7) /* Bit 7: Receive FIFO full */
+#define SPI_FIFOSTAT_TXLVL_SHIFT (8) /* Bits 8-12: Transmit FIFO current level */
+#define SPI_FIFOSTAT_TXLVL_MASK (31 << SPI_FIFOSTAT_TXLVL_SHIFT)
+#define SPI_FIFOSTAT_RXLVL_SHIFT (16) /* Bits 16-20: Receive FIFO current level */
+#define SPI_FIFOSTAT_RXLVL_MASK (31 << SPI_FIFOSTAT_RXLVL_SHIFT)
+
/* FIFO trigger level settings for interrupt and DMA request */
-#define SPI_FIFOTRIG_
-/* FIFO interrupt enable set (enable) and read register */
-#define SPI_FIFOINTENSET_
-/* FIFO interrupt enable clear (disable) and read register */
-#define SPI_FIFOINTENCLR_
-/* FIFO interrupt status register */
-#define SPI_FIFOINTSTAT_
+
+#define SPI_FIFOTRIG_TXLVLENA (1 << 0) /* Bit 0: Transmit FIFO level trigger enable */
+#define SPI_FIFOTRIG_RXLVLENA (1 << 1) /* Bit 1: Receive FIFO level trigger enable */
+#define SPI_FIFOTRIG_TXLVL_SHIFT (8) /* Bits 8-11: Transmit FIFO level trigger point */
+#define SPI_FIFOTRIG_TXLVL_MASK (15 << SPI_FIFOTRIG_TXLVL_SHIFT)
+# define SPI_FIFOTRIG_TXLVL(n) ((uint32_t)(n) << SPI_FIFOTRIG_TXLVL_SHIFT)
+# define SPI_FIFOTRIG_TXLVL_EMPTY (0 << SPI_FIFOTRIG_TXLVL_SHIFT)
+# define SPI_FIFOTRIG_TXLVL_NOTFULL (7 << SPI_FIFOTRIG_TXLVL_SHIFT)
+#define SPI_FIFOTRIG_RXLVL_SHIFT (16) /* Bits 16-19: Receive FIFO level trigger point */
+#define SPI_FIFOTRIG_RXLVL_MASK (15 << SPI_FIFOTRIG_RXLVL_SHIFT)
+# define SPI_FIFOTRIG_RXLVL(n) ((uint32_t)((n)-1) << SPI_FIFOTRIG_RXLVL_SHIFT)
+# define SPI_FIFOTRIG_RXLVL_NOTEMPTY (0 << SPI_FIFOTRIG_RXLVL_SHIFT)
+# define SPI_FIFOTRIG_RXLVL_FULL (7 << SPI_FIFOTRIG_RXLVL_SHIFT)
+
+/* FIFO interrupt enable set (enable) and read register, FIFO interrupt enable clear (disable)
+ * and read register, and FIFO interrupt status register
+ */
+
+#define SPI_FIFOINT_TXERR (1 << 0) /* Bit 0: Transmit error interrupt */
+#define SPI_FIFOINT_RXERR (1 << 1) /* Bit 1: Receive error interrupt */
+#define SPI_FIFOINT_TXLVL (1 << 2) /* Bit 2: Tx FIFO level reached interrupt */
+#define SPI_FIFOINT_RXLVL (1 << 3) /* Bit 3: Rx FIFO level reached interrupt */
+#define SPI_FIFOINTSTAT_PERINT (1 << 4) /* Bit 4: Peripheral interrupt (status only) */
+
/* FIFO write data */
-#define SPI_FIFOWR_
-/* FIFO read data */
-#define SPI_FIFORD_
-/* FIFO data read with no FIFO pop */
-#define SPI_FIFORDNOPOP_
+
+#define SPI_FIFOWR_TXDATA_SHIFT (0) /* Bits 0-15: Transmit data to the FIFO */
+#define SPI_FIFOWR_TXDATA_MASK (0xffff << SPI_FIFOWR_TXDATA_SHIFT)
+# define SPI_FIFOWR_TXDATA(n) ((uint32_t)(n) << SPI_FIFOWR_TXDATA_SHIFT)
+#define SPI_FIFOWR_TXSSELN_SHIFT (16) /* Bits 16-19: Transmit Slave Selects */
+#define SPI_FIFOWR_TXSSELN_MASK (15 << SPI_FIFOWR_TXSSELN_SHIFT)
+# define SPI_FIFOWR_TXSSELN_ALL (15 << SPI_FIFOWR_TXSSELN_SHIFT)
+# define SPI_FIFOWR_TXSSEL0N (1 << 16) /* Bit 16: Transmit Slave Select */
+# define SPI_FIFOWR_TXSSEL1N (1 << 17) /* Bit 17: Transmit Slave Select */
+# define SPI_FIFOWR_TXSSEL2N (1 << 18) /* Bit 18: Transmit Slave Select */
+# define SPI_FIFOWR_TXSSEL3N (1 << 19) /* Bit 19: Transmit Slave Select */
+#define SPI_FIFOWR_EOT (1 << 20) /* Bit 20: End of Transfer */
+#define SPI_FIFOWR_EOF (1 << 21) /* Bit 21: End of Frame */
+#define SPI_FIFOWR_RXIGNORE (1 << 22) /* Bit 22: Receive Ignore */
+#define SPI_FIFOWR_LEN_SHIFT (24) /* Bits 24-27: Data Length */
+#define SPI_FIFOWR_LEN_MASK (15 << SPI_FIFOWR_LEN_SHIFT)
+# define SPI_FIFOWR_LEN(n) ((uint32_t)((n)-1) << SPI_FIFOWR_LEN_SHIFT)
+
+/* FIFO read data and FIFO data read with no FIFO pop */
+
+#define SPI_FIFORD_RXDATA_SHIFT (0) /* Bits 0-15: Received data from the FIFO */
+#define SPI_FIFORD_RXDATA_MASK (0xffff << SPI_FIFORD_RXDATA_SHIFT)
+#define SPI_FIFORD_RXSSELN_SHIFT (16) /* Bits 16-19: Slave Selects for receive */
+#define SPI_FIFORD_RXSSELN_MASK (15 << SPI_FIFORD_RXSSELN_SHIFT)
+# define SPI_FIFORD_RXSSEL0N (1 << 16) /* Bit 16: Slave Select for receive */
+# define SPI_FIFORD_RXSSEL1N (1 << 17) /* Bit 17: Slave Select for receive */
+# define SPI_FIFORD_RXSSEL2N (1 << 18) /* Bit 18: Slave Select for receive */
+# define SPI_FIFORD_RXSSEL3N (1 << 19) /* Bit 19: Slave Select for receive */
+#define SPI_FIFORD_SOT (1 << 20) /* Bit 20: Start of Transfer flag */
+
/* SPI module Identification */
-#define SPI_ID_
+
+#define SPI_ID_APERTURE_SHIFT (0) /* Bits 0-7: Aperture encoded as (aperture size/4K) -1 */
+#define SPI_ID_APERTURE_MASK (0xff << SPI_ID_APERTURE_SHIFT)
+#define SPI_ID_MINORREV_SHIFT (8) /* Bits 8-11: Minor revision of module implementation */
+#define SPI_ID_MINORREV_MASK (15 << SPI_ID_MINORREV_SHIFT)
+#define SPI_ID_MAJORREV_SHIFT (12) /* Bits 12-15: Major revision of module implementation */
+#define SPI_ID_MAJORREV_MASK (15 << SPI_ID_MAJORREV_SHIFT)
+#define SPI_ID_ID_SHIFT (15) /* Bits 16-31: Unique module identifier for this IP block */
+#define SPI_ID_ID_MASK (0xffff << SPI_ID_ID_SHIFT)
#endif /* __ARCH_ARM_SRC_LPC54XX_CHIP_LPC54_SPI_H */
diff --git a/arch/arm/src/lpc54xx/lpc54_spi_master.c b/arch/arm/src/lpc54xx/lpc54_spi_master.c
index 665c1a4242d..35dd60ed8f5 100644
--- a/arch/arm/src/lpc54xx/lpc54_spi_master.c
+++ b/arch/arm/src/lpc54xx/lpc54_spi_master.c
@@ -1,7 +1,7 @@
/****************************************************************************
* arch/arm/src/lpc54xx/lpc54_spi.c
*
- * Copyright (C) 2017 Gregory Nutt. All rights reserved.
+ * Copyright (C) 2017-2018 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt
*
* Redistribution and use in source and binary forms, with or without
@@ -33,6 +33,16 @@
*
****************************************************************************/
+/* TODO:
+ *
+ * - There are no interrupt driven transfers, only polled. I don't
+ * consider this a significant problem because of the higher rate that
+ * would be necessary for interrupt driven transfers.
+ * - Integrate DMA transfers. This is fairly important because it can
+ * a) improve the data transfer rates and b) free the CPU when the
+ * SPI driver would otherwise be stuck in a tight polling loop.
+ */
+
/****************************************************************************
* Included Files
****************************************************************************/
@@ -59,6 +69,7 @@
#include "chip/lpc54_spi.h"
#include "lpc54_config.h"
#include "lpc54_enableclk.h"
+#include "lpc54_gpio.h"
#include "lpc54_spi_master.h"
#ifdef HAVE_SPI_MASTER_DEVICE
@@ -67,74 +78,166 @@
* Pre-processor Definitions
****************************************************************************/
+#define SPI_DUMMYDATA8 0xff
+#define SPI_DUMMYDATA16 0xffff
+
+#define SPI_MINWIDTH 4
+#ifdef CONFIG_LPC54_SPI_WIDEDATA
+# define SPI_MAXWIDTH 16
+#else
+# define SPI_MAXWIDTH 8
+#endif
+
/****************************************************************************
* Private Types
****************************************************************************/
-/* This structure descibes the state of the SSP driver */
+/* This structure describes the state of the SSP driver */
struct lpc54_spidev_s
{
- struct spi_dev_s dev; /* Externally visible part of the SPI interface */
- uintptr_t base; /* Base address of Flexcomm registers */
- sem_t exclsem; /* Held while chip is selected for mutual exclusion */
- uint32_t fclock; /* Flexcomm function clock frequency */
- uint32_t frequency; /* Requested clock frequency */
- uint32_t actual; /* Actual clock frequency */
- uint16_t irq; /* Flexcomm IRQ number */
- uint8_t nbits; /* Width of word in bits (8 to 16) */
- uint8_t mode; /* Mode 0,1,2,3 */
+ struct spi_dev_s dev; /* Externally visible part of the SPI interface */
+ uintptr_t base; /* Base address of Flexcomm registers */
+ sem_t exclsem; /* Held while chip is selected for mutual exclusion */
+ uint32_t fclock; /* Flexcomm function clock frequency */
+ uint32_t frequency; /* Requested clock frequency */
+ uint32_t actual; /* Actual clock frequency */
+ uint16_t irq; /* Flexcomm IRQ number */
+ uint8_t nbits; /* Width of word in bits (SPI_MINWIDTH to SPI_MAXWIDTH) */
+ uint8_t mode; /* Mode 0,1,2,3 */
+};
+
+/* These structures describes the Rx side of an 8- or 16-bit SPI data
+ * exchange.
+ */
+
+struct lpc54_rxtransfer8_s
+{
+ FAR uint8_t *rxptr; /* Pointer into receive buffer */
+ unsigned int remaining; /* Bytes remaining in the receive buffer */
+ unsigned int expected; /* Bytes expected to be received */
+};
+
+#ifdef CONFIG_LPC54_SPI_WIDEDATA
+struct lpc54_rxtransfer16_s
+{
+ FAR uint16_t *rxptr; /* Pointer into receive buffer */
+ unsigned int remaining; /* Hwords remaining in the receive buffer */
+ unsigned int expected; /* Hwords expected to be received */
+};
+#endif
+
+/* These structures describes the Tx side of an 8- or 16-bit SPI data
+ * exchange.
+ */
+
+struct lpc54_txtransfer8_s
+{
+ uint32_t txctrl; /* Tx control bits */
+ FAR const uint8_t *txptr; /* Pointer into transmit buffer */
+ unsigned int remaining; /* Bytes remaining in the transmit buffer */
+};
+
+#ifdef CONFIG_LPC54_SPI_WIDEDATA
+struct lpc54_txtransfer16_s
+{
+ uint32_t txctrl; /* Tx control bits */
+ FAR const uint16_t *txptr; /* Pointer into transmit buffer */
+ unsigned int remaining; /* Hwords remaining in the transmit buffer */
+};
+#endif
+
+struct lpc54_txdummy_s
+{
+ uint32_t txctrl; /* Tx control bits */
+ unsigned int remaining; /* Bytes remaining in the transmit buffer */
};
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
-static inline bool lpc54_spi_16bitmode(FAR struct lpc54_spidev_s *priv);
+/* Transfer helpers */
+
+static inline unsigned int lpc54_spi_fifodepth(FAR struct lpc54_spidev_s *priv);
+static inline bool lpc54_spi_txavailable(FAR struct lpc54_spidev_s *priv);
+static inline bool lpc54_spi_rxavailable(FAR struct lpc54_spidev_s *priv);
+
+static void lpc54_spi_resetfifos(FAR struct lpc54_spidev_s *priv);
+static void lpc54_spi_rxtransfer8(FAR struct lpc54_spidev_s *priv,
+ FAR struct lpc54_rxtransfer8_s *xfr);
+#ifdef CONFIG_LPC54_SPI_WIDEDATA
+static void lpc54_spi_rxtransfer16(FAR struct lpc54_spidev_s *priv,
+ FAR struct lpc54_rxtransfer16_s *xfr);
+#endif
+static bool lpc54_spi_txtransfer8(FAR struct lpc54_spidev_s *priv,
+ FAR struct lpc54_txtransfer8_s *xfr);
+#ifdef CONFIG_LPC54_SPI_WIDEDATA
+static bool lpc54_spi_txtransfer16(FAR struct lpc54_spidev_s *priv,
+ FAR struct lpc54_txtransfer16_s *xfr);
+#endif
+static bool lpc54_spi_txdummy(FAR struct lpc54_spidev_s *priv,
+ FAR struct lpc54_txdummy_s *xfr);
+#ifdef CONFIG_SPI_EXCHANGE
+static void lpc54_spi_exchange8(FAR struct lpc54_spidev_s *priv,
+ FAR const void *txbuffer, FAR void *rxbuffer,
+ size_t nwords);
+#ifdefCONFIG_LPC54_SPI_WIDEDATA
+static void lpc54_spi_exchange16(FAR struct lpc54_spidev_s *priv,
+ FAR const void *txbuffer, FAR void *rxbuffer,
+ size_t nwords);
+#endif
+#endif
+static void lpc54_spi_sndblock8(FAR struct lpc54_spidev_s *priv,
+ FAR const void *buffer, size_t nwords);
+#ifdef CONFIG_LPC54_SPI_WIDEDATA
+static void lpc54_spi_sndblock16(FAR struct lpc54_spidev_s *priv,
+ FAR const void *buffer, size_t nwords);
+#endif
+static void lpc54_spi_recvblock8(FAR struct lpc54_spidev_s *priv,
+ FAR void *buffer, size_t nwords);
+#ifdef CONFIG_LPC54_SPI_WIDEDATA
+static void lpc54_spi_recvblock16(FAR struct lpc54_spidev_s *priv,
+ FAR void *buffer, size_t nwords);
+#endif
/* SPI methods */
static int lpc54_spi_lock(FAR struct spi_dev_s *dev, bool lock);
-static void lpc54_spi_select(FAR struct spi_dev_s *dev, uint32_t devid,
- bool selected);
static uint32_t lpc54_spi_setfrequency(FAR struct spi_dev_s *dev,
uint32_t frequency);
static void lpc54_spi_setmode(FAR struct spi_dev_s *dev,
enum spi_mode_e mode);
static void lpc54_spi_setbits(FAR struct spi_dev_s *dev, int nbits);
static uint16_t lpc54_spi_send(FAR struct spi_dev_s *dev, uint16_t ch);
-#ifdef CONFIG_LPC54_SPI_MASTER_DMA
-static void lpc54_spi_exchange_nodma(FAR struct spi_dev_s *dev,
- FAR const void *txbuffer, FAR void *rxbuffer,
- size_t nwords)
-#endif
+#ifdef CONFIG_SPI_EXCHANGE
static void lpc54_spi_exchange(FAR struct spi_dev_s *dev,
FAR const void *txbuffer, FAR void *rxbuffer,
size_t nwords);
-#ifndef CONFIG_SPI_EXCHANGE
+#endif
static void lpc54_spi_sndblock(FAR struct spi_dev_s *dev,
FAR const void *buffer, size_t nwords);
static void lpc54_spi_recvblock(FAR struct spi_dev_s *dev,
FAR void *buffer, size_t nwords);
-#endif
/****************************************************************************
* Private Data
****************************************************************************/
-static const struct spi_ops_s g_spi_ops =
+#ifdef CONFIG_LPC54_SPI0_MASTER
+static const struct spi_ops_s g_spi0_ops =
{
.lock = lpc54_spi_lock,
- .select = lpc54_spiselect,
+ .select = lpc54_spi0_select, /* Provided externally */
.setfrequency = lpc54_spi_setfrequency,
.setmode = lpc54_spi_setmode,
.setbits = lpc54_spi_setbits,
#ifdef CONFIG_SPI_HWFEATURES
- .hwfeatures = 0, /* Not supported */
+ .hwfeatures = NULL, /* Not supported */
#endif
- .status = lpc54_spistatus,
+ .status = lpc54_spi0_status, /* Provided externally */
#ifdef CONFIG_SPI_CMDDATA
- .cmddata = lpc54_spicmddata,
+ .cmddata = lpc54_spi0_cmddata, /* Provided externally */
#endif
.send = lpc54_spi_send,
#ifdef CONFIG_SPI_EXCHANGE
@@ -144,40 +247,300 @@ static const struct spi_ops_s g_spi_ops =
.recvblock = lpc54_spi_recvblock,
#endif
#ifdef CONFIG_SPI_CALLBACK
- .registercallback = lpc54_spiregister, /* Provided externally */
+ .registercallback = lpc54_spi0_register, /* Provided externally */
#else
- .registercallback = 0, /* Not implemented */
+ .registercallback = NULL, /* Not implemented */
#endif
};
-#ifdef CONFIG_LPC54_I2C0_MASTER
static struct lpc54_spidev_s g_spi0_dev;
#endif
-#ifdef CONFIG_LPC54_I2C1_MASTER
+
+#ifdef CONFIG_LPC54_SPI1_MASTER
+static const struct spi_ops_s g_spi1_ops =
+{
+ .lock = lpc54_spi_lock,
+ .select = lpc54_spi1_select, /* Provided externally */
+ .setfrequency = lpc54_spi_setfrequency,
+ .setmode = lpc54_spi_setmode,
+ .setbits = lpc54_spi_setbits,
+#ifdef CONFIG_SPI_HWFEATURES
+ .hwfeatures = NULL, /* Not supported */
+#endif
+ .status = lpc54_spi1_status, /* Provided externally */
+#ifdef CONFIG_SPI_CMDDATA
+ .cmddata = lpc54_spi1_cmddata, /* Provided externally */
+#endif
+ .send = lpc54_spi_send,
+#ifdef CONFIG_SPI_EXCHANGE
+ .exchange = lpc54_spi_exchange,
+#else
+ .sndblock = lpc54_spi_sndblock,
+ .recvblock = lpc54_spi_recvblock,
+#endif
+#ifdef CONFIG_SPI_CALLBACK
+ .registercallback = lpc54_spi1_register, /* Provided externally */
+#else
+ .registercallback = NULL, /* Not implemented */
+#endif
+};
+
static struct lpc54_spidev_s g_spi1_dev;
#endif
-#ifdef CONFIG_LPC54_I2C2_MASTER
+
+#ifdef CONFIG_LPC54_SPI2_MASTER
+static const struct spi_ops_s g_spi2_ops =
+{
+ .lock = lpc54_spi_lock,
+ .select = lpc54_spi2_select, /* Provided externally */
+ .setfrequency = lpc54_spi_setfrequency,
+ .setmode = lpc54_spi_setmode,
+ .setbits = lpc54_spi_setbits,
+#ifdef CONFIG_SPI_HWFEATURES
+ .hwfeatures = NULL, /* Not supported */
+#endif
+ .status = lpc54_spi2_status, /* Provided externally */
+#ifdef CONFIG_SPI_CMDDATA
+ .cmddata = lpc54_spi2_cmddata, /* Provided externally */
+#endif
+ .send = lpc54_spi_send,
+#ifdef CONFIG_SPI_EXCHANGE
+ .exchange = lpc54_spi_exchange,
+#else
+ .sndblock = lpc54_spi_sndblock,
+ .recvblock = lpc54_spi_recvblock,
+#endif
+#ifdef CONFIG_SPI_CALLBACK
+ .registercallback = lpc54_spi2_register, /* Provided externally */
+#else
+ .registercallback = NULL, /* Not implemented */
+#endif
+};
+
static struct lpc54_spidev_s g_spi2_dev;
#endif
-#ifdef CONFIG_LPC54_I2C3_MASTER
+
+#ifdef CONFIG_LPC54_SPI3_MASTER
+static const struct spi_ops_s g_spi3_ops =
+{
+ .lock = lpc54_spi_lock,
+ .select = lpc54_spi3_select, /* Provided externally */
+ .setfrequency = lpc54_spi_setfrequency,
+ .setmode = lpc54_spi_setmode,
+ .setbits = lpc54_spi_setbits,
+#ifdef CONFIG_SPI_HWFEATURES
+ .hwfeatures = NULL, /* Not supported */
+#endif
+ .status = lpc54_spi3_status, /* Provided externally */
+#ifdef CONFIG_SPI_CMDDATA
+ .cmddata = lpc54_spi3_cmddata, /* Provided externally */
+#endif
+ .send = lpc54_spi_send,
+#ifdef CONFIG_SPI_EXCHANGE
+ .exchange = lpc54_spi_exchange,
+#else
+ .sndblock = lpc54_spi_sndblock,
+ .recvblock = lpc54_spi_recvblock,
+#endif
+#ifdef CONFIG_SPI_CALLBACK
+ .registercallback = lpc54_spi3_register, /* Provided externally */
+#else
+ .registercallback = NULL, /* Not implemented */
+#endif
+};
+
static struct lpc54_spidev_s g_spi3_dev;
#endif
-#ifdef CONFIG_LPC54_I2C4_MASTER
+
+#ifdef CONFIG_LPC54_SPI4_MASTER
+static const struct spi_ops_s g_spi4_ops =
+{
+ .lock = lpc54_spi_lock,
+ .select = lpc54_spi4_select, /* Provided externally */
+ .setfrequency = lpc54_spi_setfrequency,
+ .setmode = lpc54_spi_setmode,
+ .setbits = lpc54_spi_setbits,
+#ifdef CONFIG_SPI_HWFEATURES
+ .hwfeatures = NULL, /* Not supported */
+#endif
+ .status = lpc54_spi4_status, /* Provided externally */
+#ifdef CONFIG_SPI_CMDDATA
+ .cmddata = lpc54_spi4_cmddata, /* Provided externally */
+#endif
+ .send = lpc54_spi_send,
+#ifdef CONFIG_SPI_EXCHANGE
+ .exchange = lpc54_spi_exchange,
+#else
+ .sndblock = lpc54_spi_sndblock,
+ .recvblock = lpc54_spi_recvblock,
+#endif
+#ifdef CONFIG_SPI_CALLBACK
+ .registercallback = lpc54_spi4_register, /* Provided externally */
+#else
+ .registercallback = NULL, /* Not implemented */
+#endif
+};
+
static struct lpc54_spidev_s g_spi4_dev;
#endif
-#ifdef CONFIG_LPC54_I2C5_MASTER
+
+#ifdef CONFIG_LPC54_SPI5_MASTER
+static const struct spi_ops_s g_spi5_ops =
+{
+ .lock = lpc54_spi_lock,
+ .select = lpc54_spi5_select, /* Provided externally */
+ .setfrequency = lpc54_spi_setfrequency,
+ .setmode = lpc54_spi_setmode,
+ .setbits = lpc54_spi_setbits,
+#ifdef CONFIG_SPI_HWFEATURES
+ .hwfeatures = NULL, /* Not supported */
+#endif
+ .status = lpc54_spi5_status, /* Provided externally */
+#ifdef CONFIG_SPI_CMDDATA
+ .cmddata = lpc54_spi5_cmddata, /* Provided externally */
+#endif
+ .send = lpc54_spi_send,
+#ifdef CONFIG_SPI_EXCHANGE
+ .exchange = lpc54_spi_exchange,
+#else
+ .sndblock = lpc54_spi_sndblock,
+ .recvblock = lpc54_spi_recvblock,
+#endif
+#ifdef CONFIG_SPI_CALLBACK
+ .registercallback = lpc54_spi5_register, /* Provided externally */
+#else
+ .registercallback = NULL, /* Not implemented */
+#endif
+};
+
static struct lpc54_spidev_s g_spi5_dev;
#endif
-#ifdef CONFIG_LPC54_I2C6_MASTER
+
+#ifdef CONFIG_LPC54_SPI6_MASTER
+static const struct spi_ops_s g_spi6_ops =
+{
+ .lock = lpc54_spi_lock,
+ .select = lpc54_spi6_select, /* Provided externally */
+ .setfrequency = lpc54_spi_setfrequency,
+ .setmode = lpc54_spi_setmode,
+ .setbits = lpc54_spi_setbits,
+#ifdef CONFIG_SPI_HWFEATURES
+ .hwfeatures = NULL, /* Not supported */
+#endif
+ .status = lpc54_spi6_status, /* Provided externally */
+#ifdef CONFIG_SPI_CMDDATA
+ .cmddata = lpc54_spi6_cmddata, /* Provided externally */
+#endif
+ .send = lpc54_spi_send,
+#ifdef CONFIG_SPI_EXCHANGE
+ .exchange = lpc54_spi_exchange,
+#else
+ .sndblock = lpc54_spi_sndblock,
+ .recvblock = lpc54_spi_recvblock,
+#endif
+#ifdef CONFIG_SPI_CALLBACK
+ .registercallback = lpc54_spi6_register, /* Provided externally */
+#else
+ .registercallback = NULL, /* Not implemented */
+#endif
+};
+
static struct lpc54_spidev_s g_spi6_dev;
#endif
-#ifdef CONFIG_LPC54_I2C7_MASTER
+
+#ifdef CONFIG_LPC54_SPI7_MASTER
+static const struct spi_ops_s g_spi7_ops =
+{
+ .lock = lpc54_spi_lock,
+ .select = lpc54_spi7_select, /* Provided externally */
+ .setfrequency = lpc54_spi_setfrequency,
+ .setmode = lpc54_spi_setmode,
+ .setbits = lpc54_spi_setbits,
+#ifdef CONFIG_SPI_HWFEATURES
+ .hwfeatures = NULL, /* Not supported */
+#endif
+ .status = lpc54_spi7_status, /* Provided externally */
+#ifdef CONFIG_SPI_CMDDATA
+ .cmddata = lpc54_spi7_cmddata, /* Provided externally */
+#endif
+ .send = lpc54_spi_send,
+#ifdef CONFIG_SPI_EXCHANGE
+ .exchange = lpc54_spi_exchange,
+#else
+ .sndblock = lpc54_spi_sndblock,
+ .recvblock = lpc54_spi_recvblock,
+#endif
+#ifdef CONFIG_SPI_CALLBACK
+ .registercallback = lpc54_spi7_register, /* Provided externally */
+#else
+ .registercallback = NULL, /* Not implemented */
+#endif
+};
+
static struct lpc54_spidev_s g_spi7_dev;
#endif
-#ifdef CONFIG_LPC54_I2C8_MASTER
+
+#ifdef CONFIG_LPC54_SPI8_MASTER
+static const struct spi_ops_s g_spi8_ops =
+{
+ .lock = lpc54_spi_lock,
+ .select = lpc54_spi8_select, /* Provided externally */
+ .setfrequency = lpc54_spi_setfrequency,
+ .setmode = lpc54_spi_setmode,
+ .setbits = lpc54_spi_setbits,
+#ifdef CONFIG_SPI_HWFEATURES
+ .hwfeatures = NULL, /* Not supported */
+#endif
+ .status = lpc54_spi8_status, /* Provided externally */
+#ifdef CONFIG_SPI_CMDDATA
+ .cmddata = lpc54_spi8_cmddata, /* Provided externally */
+#endif
+ .send = lpc54_spi_send,
+#ifdef CONFIG_SPI_EXCHANGE
+ .exchange = lpc54_spi_exchange,
+#else
+ .sndblock = lpc54_spi_sndblock,
+ .recvblock = lpc54_spi_recvblock,
+#endif
+#ifdef CONFIG_SPI_CALLBACK
+ .registercallback = lpc54_spi8_register, /* Provided externally */
+#else
+ .registercallback = NULL, /* Not implemented */
+#endif
+};
+
static struct lpc54_spidev_s g_spi8_dev;
#endif
-#ifdef CONFIG_LPC54_I2C9_MASTER
+
+#ifdef CONFIG_LPC54_SPI9_MASTER
+static const struct spi_ops_s g_spi9_ops =
+{
+ .lock = lpc54_spi_lock,
+ .select = lpc54_spi9_select, /* Provided externally */
+ .setfrequency = lpc54_spi_setfrequency,
+ .setmode = lpc54_spi_setmode,
+ .setbits = lpc54_spi_setbits,
+#ifdef CONFIG_SPI_HWFEATURES
+ .hwfeatures = NULL, /* Not supported */
+#endif
+ .status = lpc54_spi9_status, /* Provided externally */
+#ifdef CONFIG_SPI_CMDDATA
+ .cmddata = lpc54_spi9_cmddata, /* Provided externally */
+#endif
+ .send = lpc54_spi_send,
+#ifdef CONFIG_SPI_EXCHANGE
+ .exchange = lpc54_spi_exchange,
+#else
+ .sndblock = lpc54_spi_sndblock,
+ .recvblock = lpc54_spi_recvblock,
+#endif
+#ifdef CONFIG_SPI_CALLBACK
+ .registercallback = lpc54_spi9_register, /* Provided externally */
+#else
+ .registercallback = NULL, /* Not implemented */
+#endif
+};
+
static struct lpc54_spidev_s g_spi9_dev;
#endif
@@ -196,49 +559,691 @@ static struct lpc54_spidev_s g_spi9_dev;
static inline void lpc54_spi_putreg(struct lpc54_spidev_s *priv,
unsigned int regoffset, uint32_t regval)
{
- putreg32(value, priv->base + regoffset);
+ putreg32(regval, priv->base + regoffset);
}
/****************************************************************************
- * Name: lpc54_spi_gettreg
+ * Name: lpc54_spi_getreg
*
* Description:
* Read the content of a register at the offset from the Flexcomm base.
*
****************************************************************************/
-static inline void lpc54_spi_gettreg(struct lpc54_spidev_s *priv,
- unsigned int regoffset)
+static inline uint32_t lpc54_spi_getreg(struct lpc54_spidev_s *priv,
+ unsigned int regoffset)
{
return getreg32(priv->base + regoffset);
}
/****************************************************************************
- * Name: lpc54_spi_16bitmode
+ * Name: lpc54_spi_fifodepth
*
* Description:
- * Check if the SPI is operating in > 8-bit mode (16-bit accesses)
+ * Return the depth of the SPI FIFOs. This is a constant value and could
+ * be hard coded.
*
* Input Parameters:
* priv - Device-specific state data
*
* Returned Value:
- * true: 16-bit mode, false: 8-bit mode
+ * The FIFO depth in words of the configured bit width.
*
****************************************************************************/
-static inline bool lpc54_spi_16bitmode(FAR struct lpc54_spidev_s *priv)
+static inline unsigned int lpc54_spi_fifodepth(FAR struct lpc54_spidev_s *priv)
{
-#warning Missing logic
+ uint32_t regval = lpc54_spi_getreg(priv, LPC54_SPI_FIFOCFG_OFFSET);
+ return ((regval & SPI_FIFOCFG_SIZE_MASK) >> SPI_FIFOCFG_SIZE_SHIFT) << 3;
+}
+
+/****************************************************************************
+ * Name: lpc54_spi_txavailable
+ *
+ * Description:
+ * Return true if the Tx FIFO is not full.
+ *
+ * Input Parameters:
+ * priv - Device-specific state data
+ *
+ * Returned Value:
+ * true: Tx FIFO is not full.
+ *
+ ****************************************************************************/
+
+static inline bool lpc54_spi_txavailable(FAR struct lpc54_spidev_s *priv)
+{
+ uint32_t regval = lpc54_spi_getreg(priv, LPC54_SPI_FIFOSTAT_OFFSET);
+ return ((regval & SPI_FIFOSTAT_TXNOTFULL) != 0);
+}
+
+/****************************************************************************
+ * Name: lpc54_spi_rxavailable
+ *
+ * Description:
+ * Return true if the Rx FIFO is not empty.
+ *
+ * Input Parameters:
+ * priv - Device-specific state data
+ *
+ * Returned Value:
+ * true: Rx FIFO is not empty.
+ *
+ ****************************************************************************/
+
+static inline bool lpc54_spi_rxavailable(FAR struct lpc54_spidev_s *priv)
+{
+ uint32_t regval = lpc54_spi_getreg(priv, LPC54_SPI_FIFOSTAT_OFFSET);
+ return ((regval & SPI_FIFOSTAT_RXNOTEMPTY) != 0);
+}
+
+/****************************************************************************
+ * Name: lpc54_spi_rxdiscard
+ *
+ * Description:
+ * Read and discard the data until the Rx FIFO is empty.
+ *
+ * Input Parameters:
+ * priv - Device-specific state data
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+static void lpc54_spi_rxdiscard(FAR struct lpc54_spidev_s *priv)
+{
+ while (lpc54_spi_rxavailable(priv))
+ {
+ (void)lpc54_spi_getreg(priv, LPC54_SPI_FIFORD_OFFSET);
+ }
+}
+
+/****************************************************************************
+ * Name: lpc54_spi_resetfifos
+ *
+ * Description:
+ * Clear Tx/Rx errors and empty FIFOs.
+ *
+ * Input Parameters:
+ * priv - Device-specific state data
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+static void lpc54_spi_resetfifos(FAR struct lpc54_spidev_s *priv)
+{
+ uint32_t regval;
+
+ /* Clear Tx/Rx errors and empty FIFOs */
+
+ regval = lpc54_spi_getreg(priv, LPC54_SPI_FIFOCFG_OFFSET);
+ regval |= (SPI_FIFOCFG_EMPTYTX | SPI_FIFOCFG_EMPTYRX);
+ lpc54_spi_putreg(priv, LPC54_SPI_FIFOCFG_OFFSET, regval);
+
+ regval = lpc54_spi_getreg(priv, LPC54_SPI_FIFOSTAT_OFFSET);
+ regval |= (SPI_FIFOSTAT_TXERR | SPI_FIFOSTAT_RXERR);
+ lpc54_spi_putreg(priv, LPC54_SPI_FIFOSTAT_OFFSET, regval);
+}
+
+/****************************************************************************
+ * Name: lpc54_spi_rxtransfer8 and lpc54_spi_rxtransfer16
+ *
+ * Description:
+ * Receive one 8- or 16-bit value from the selected SPI device.
+ *
+ * Input Parameters:
+ * priv - Device-specific state data
+ * xfr - Describes the Rx transfer
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+static void lpc54_spi_rxtransfer8(FAR struct lpc54_spidev_s *priv,
+ FAR struct lpc54_rxtransfer8_s *xfr)
+{
+ /* Read one byte if available and expected */
+
+ if (lpc54_spi_rxavailable(priv))
+ {
+ /* There is something in the Rx FIFO to be read. Are we expecting
+ * data in the Rx FIFO? Is there space available in the Rx buffer?
+ */
+
+ if (xfr->expected == 0 || xfr->remaining == 0)
+ {
+ /* No.. then just read and discard the data until the Rx FIFO is empty */
+
+ lpc54_spi_rxdiscard(priv);
+ xfr->expected = 0;
+ }
+ else
+ {
+ /* Read and transfer one byte */
+
+ *xfr->rxptr = lpc54_spi_getreg(priv, LPC54_SPI_FIFORD_OFFSET);
+
+ /* Update pointers and counts */
+
+ xfr->rxptr++;
+ xfr->remaining--;
+ xfr->expected--;
+ }
+ }
+}
+
+#ifdef CONFIG_LPC54_SPI_WIDEDATA
+static void lpc54_spi_rxtransfer16(FAR struct lpc54_spidev_s *priv,
+ FAR struct lpc54_rxtransfer16_s *xfr)
+{
+ /* Read one HWord if available and expected */
+
+ if (lpc54_spi_rxavailable(priv))
+ {
+ /* There is something in the Rx FIFO to be read. Are we expecting
+ * data in the Rx FIFO? Is there space available in the Rx buffer?
+ */
+
+ if (xfr->expected == 0 || xfr->remaining == 0)
+ {
+ /* No.. then just read and discard the data until the Rx FIFO
+ * is empty.
+ */
+
+ lpc54_spi_rxdiscard(priv);
+ xfr->expected = 0;
+ }
+ else
+ {
+ /* Read and transfer HWord */
+
+ *xfr->rxptr = lpc54_spi_getreg(priv, LPC54_SPI_FIFORD_OFFSET);
+
+ /* Update pointers and counts */
+
+ xfr->rxptr++;
+ xfr->remaining--;
+ xfr->expected--;
+ }
+ }
+}
+#endif
+
+/****************************************************************************
+ * Name: lpc54_spi_txtransfer8 and lpc54_spi_txtransfer16
+ *
+ * Description:
+ * Send one 8- or 16-bit value to the selected SPI device.
+ *
+ * Input Parameters:
+ * priv - Device-specific state data
+ * xfr - Describes the Tx transfer
+ *
+ * Returned Value:
+ * true: The value was added to the TxFIFO
+ *
+ ****************************************************************************/
+
+static bool lpc54_spi_txtransfer8(FAR struct lpc54_spidev_s *priv,
+ FAR struct lpc54_txtransfer8_s *xfr)
+{
+ uint32_t regval;
+
+ /* Transmit if txFIFO is not full and there is more Tx data to be sent */
+
+ if (lpc54_spi_txavailable(priv) && xfr->remaining > 0)
+ {
+ /* Get the next byte to be sent */
+
+ regval = *xfr->txptr;
+
+ /* And send it */
+
+ regval |= xfr->txctrl;
+ lpc54_spi_putreg(priv, LPC54_SPI_FIFOWR_OFFSET, regval);
+
+ /* Update pointers and counts */
+
+ xfr->txptr++;
+ xfr->remaining--;
+
+ return true;
+ }
+
return false;
}
+#ifdef CONFIG_LPC54_SPI_WIDEDATA
+static bool lpc54_spi_txtransfer16(FAR struct lpc54_spidev_s *priv,
+ FAR struct lpc54_txtransfer16_s *xfr)
+{
+ uint32_t regval;
+
+ /* Transmit if txFIFO is not full and there is more Tx data to be sent */
+
+ if (lpc54_spi_txavailable(priv) && xfr->remaining > 0)
+ {
+ /* Get the next byte to be sent */
+
+ regval = *xfr->txptr;
+
+ /* And send it */
+
+ regval |= xfr->txctrl;
+ lpc54_spi_putreg(priv, LPC54_SPI_FIFOWR_OFFSET, regval);
+
+ /* Update pointers and counts */
+
+ xfr->txptr++;
+ xfr->remaining--;
+
+ return true;
+ }
+
+ return false;
+}
+#endif
+
+/****************************************************************************
+ * Name: lpc54_spi_txdummy
+ *
+ * Description:
+ * Send dummy Tx data when we really only care about the Rx data.
+ *
+ * Input Parameters:
+ * priv - Device-specific state data
+ * xfr - Describes the Tx transfer
+ *
+ * Returned Value:
+ * true: The dummy value was added to the TxFIFO
+ *
+ ****************************************************************************/
+
+static bool lpc54_spi_txdummy(FAR struct lpc54_spidev_s *priv,
+ FAR struct lpc54_txdummy_s *xfr)
+{
+ /* Transmit if txFIFO is not full and there is more Tx data to be sent */
+
+ if (lpc54_spi_txavailable(priv) && xfr->remaining > 0)
+ {
+ /* Send the dummy data */
+
+ lpc54_spi_putreg(priv, LPC54_SPI_FIFOWR_OFFSET, xfr->txctrl);
+
+ /* Update counts */
+
+ xfr->remaining--;
+ return true;
+ }
+
+ return false;
+}
+
+/****************************************************************************
+ * Name: lpc54_spi_exchange8 and lpc54_spi_exchange16
+ *
+ * Description:
+ * Implements the SPI exchange method for the case of 8- and 16-bit transfers.
+ *
+ * Input Parameters:
+ * priv - Device-specific state data
+ * txbuffer - A pointer to the buffer of data to be sent
+ * rxbuffer - A pointer to a buffer in which to receive data
+ * nwords - the length of data to be exchanged in units of words.
+ * The wordsize is determined by the number of bits-per-word
+ * selected for the SPI interface. If nbits <= 8, the data is
+ * packed into uint8_t's; if nbits >8, the data is packed into
+ * uint16_t's
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_SPI_EXCHANGE
+static void lpc54_spi_exchange8(FAR struct lpc54_spidev_s *priv,
+ FAR const void *txbuffer, FAR void *rxbuffer,
+ size_t nwords)
+{
+ struct lpc54_rxtransfer8_s rxtransfer;
+ struct lpc54_txtransfer8_s txtransfer;
+ unsigned int depth;
+
+ DEBUGASSERT(rxbuffer != NULL && txbuffer != NULL);
+
+ /* Get the FIFO depth */
+
+ depth = lpc54_spi_fifodepth(priv);
+
+ /* Set up the transfer data */
+
+ txtransfer.txctrl = SPI_FIFOWR_LEN(priv->nbits) | SPI_FIFOWR_TXSSELN_ALL;
+ txtransfer.txptr = (FAR uint8_t *)txbuffer;
+ txtransfer.remaining = nwords;
+ rxtransfer.rxptr = (FAR uint8_t *)rxbuffer;
+ rxtransfer.remaining = nwords;
+ rxtransfer.expected = 0;
+
+ /* Clear Tx/Rx errors and empty FIFOs */
+
+ lpc54_spi_resetfifos(priv);
+
+ /* Loop until all Tx data has been sent and until all Rx data has been
+ * received.
+ */
+
+ while (txtransfer.remaining != 0 || rxtransfer.remaining != 0)
+ {
+ /* Transfer one byte from the Rx FIFO to the caller's Rx buffer */
+
+ lpc54_spi_rxtransfer8(priv, &rxtransfer);
+
+ /* If sending another byte would exceed the capacity of the Rx FIFO
+ * then read-only until there space freed.
+ */
+
+ if (rxtransfer.expected < depth)
+ {
+ /* Attempt to transfer one byte from the caller's Tx buffer to
+ * the Tx FIFO.
+ */
+
+ if (lpc54_spi_txtransfer8(priv, &txtransfer))
+ {
+ /* Increment the Rx expected count if successful */
+
+ rxtransfer.expected++;
+ }
+ }
+ }
+}
+#endif /* CONFIG_SPI_EXCHANGE */
+
+#if defined(CONFIG_SPI_EXCHANGE) && defined(CONFIG_LPC54_SPI_WIDEDATA)
+static void lpc54_spi_exchange16(FAR struct lpc54_spidev_s *priv,
+ FAR const void *txbuffer, FAR void *rxbuffer,
+ size_t nwords)
+{
+ struct lpc54_rxtransfer16_s rxtransfer;
+ struct lpc54_txtransfer16_s txtransfer;
+ uint32_t regval;
+ unsigned int depth;
+
+ DEBUGASSERT(rxbuffer != NULL && ((uintptr_t)rxbuffer & 1) == 0);
+ DEBUGASSERT(txbuffer != NULL && ((uintptr_t)txbuffer & 1) == 0);
+
+ /* Get the FIFO depth */
+
+ depth = lpc54_spi_fifodepth(priv);
+
+ /* Set up the transfer data */
+
+ txtransfer.txctrl = SPI_FIFOWR_LEN(priv->nbits) | SPI_FIFOWR_TXSSELN_ALL;
+ txtransfer.txptr = (FAR uint16_t *)txbuffer;
+ txtransfer.remaining = nwords;
+ rxtransfer.rxptr = (FAR uint16_t *)rxbuffer;
+ rxtransfer.remaining = nwords;
+ rxtransfer.expected = 0;
+
+ /* Clear Tx/Rx errors and empty FIFOs */
+
+ lpc54_spi_resetfifos(priv);
+
+ /* Loop until all Tx data has been sent and until all Rx data has been
+ * received.
+ */
+
+ while (txtransfer.remaining || rxtransfer.remaining || rxtransfer.expected)
+ {
+ /* Transfer one HWord from the Rx FIFO to the caller's Rx buffer */
+
+ lpc54_spi_rxtransfer16(priv, &rxtransfer);
+
+ /* If sending another byte would exceed the capacity of the Rx FIFO
+ * then read-only until there space freed.
+ */
+
+ if (rxtransfer.expected < depth)
+ {
+ /* Attempt to send one more byte */
+
+ if (lpc54_spi_txtransfer16(priv, &txtransfer))
+ {
+ /* Increment the Rx expected count if successful */
+
+ rxtransfer.expected++;
+ }
+ }
+ }
+}
+#endif /* CONFIG_SPI_EXCHANGE && CONFIG_LPC54_SPI_WIDEDATA */
+
+/****************************************************************************
+ * Name: lpc54_spi_sndblock8 and lpc54_spi_sndblock16
+ *
+ * Description:
+ * Implements the SPI sndblock method for the case of 8- and 16-bit
+ * transfers.
+ *
+ * Input Parameters:
+ * priv - Device-specific state data
+ * buffer - A pointer to the buffer of data to be sent
+ * nwords - the length of data to send from the buffer in number of words.
+ * The wordsize is determined by the number of bits-per-word
+ * selected for the SPI interface. If nbits <= 8, the data is
+ * packed into uint8_t's; if nbits >8, the data is packed into
+ * uint16_t's
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+static void lpc54_spi_sndblock8(FAR struct lpc54_spidev_s *priv,
+ FAR const void *buffer, size_t nwords)
+{
+ struct lpc54_txtransfer8_s txtransfer;
+
+ DEBUGASSERT(buffer != NULL);
+
+ /* Set up the transfer data. NOTE that we are ignoring returned Rx data */
+
+ txtransfer.txctrl = SPI_FIFOWR_RXIGNORE | SPI_FIFOWR_LEN(priv->nbits) |
+ SPI_FIFOWR_TXSSELN_ALL;
+ txtransfer.txptr = (FAR uint8_t *)buffer;
+ txtransfer.remaining = nwords;
+
+ /* Clear Tx/Rx errors and empty FIFOs */
+
+ lpc54_spi_resetfifos(priv);
+
+ /* Loop until all Tx data has been sent */
+
+ while (txtransfer.remaining != 0)
+ {
+ /* Attempt to transfer one byte from the caller's Tx buffer to the
+ * Tx FIFO.
+ */
+
+ (void)lpc54_spi_txtransfer8(priv, &txtransfer);
+ }
+}
+
+#ifdef CONFIG_LPC54_SPI_WIDEDATA
+static void lpc54_spi_sndblock16(FAR struct lpc54_spidev_s *priv,
+ FAR const void *buffer, size_t nwords)
+{
+ struct lpc54_txtransfer16_s txtransfer;
+
+ DEBUGASSERT(buffer != NULL);
+
+ /* Set up the transfer data. NOTE that we are ignoring returned Rx data */
+
+ txtransfer.txctrl = SPI_FIFOWR_RXIGNORE | SPI_FIFOWR_LEN(priv->nbits) |
+ SPI_FIFOWR_TXSSELN_ALL;
+ txtransfer.txptr = (FAR uint16_t *)buffer;
+ txtransfer.remaining = nwords;
+
+ /* Clear Tx/Rx errors and empty FIFOs */
+
+ lpc54_spi_resetfifos(priv);
+
+ /* Loop until all Tx data has been sent and until all Rx data has been
+ * received.
+ */
+
+ while (txtransfer.remaining != 0)
+ {
+ /* Attempt to transfer one byte from the caller's Tx buffer to the
+ * Tx FIFO.
+ */
+
+ lpc54_spi_txtransfer16(priv, &txtransfer);
+ }
+}
+#endif /*CONFIG_LPC54_SPI_WIDEDATA */
+
+/****************************************************************************
+ * Name: lpc54_spi_recvblock8 and lpc54_spi_recvblock16
+ *
+ * Description:
+ * Implements the SPI recvblock method for the case of 8- and 16-bit
+ * transfers.
+ *
+ * Input Parameters:
+ * priv - Device-specific state data
+ * buffer - A pointer to the buffer in which to receive data
+ * nwords - the length of data that can be received in the buffer in
+ * number of words. The wordsize is determined by the number of
+ * bits-per-word selected for the SPI interface. If nbits <= 8,
+ * the data is packed into uint8_t's; if nbits >8, the data is
+ * packed into uint16_t's
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+static void lpc54_spi_recvblock8(FAR struct lpc54_spidev_s *priv,
+ FAR void *buffer, size_t nwords)
+{
+ struct lpc54_rxtransfer8_s rxtransfer;
+ struct lpc54_txdummy_s txtransfer;
+ unsigned int depth;
+
+ DEBUGASSERT(buffer != NULL);
+
+ /* Get the FIFO depth */
+
+ depth = lpc54_spi_fifodepth(priv);
+
+ /* Set up the transfer data */
+
+ txtransfer.txctrl = SPI_DUMMYDATA8 | SPI_FIFOWR_LEN(priv->nbits) |
+ SPI_FIFOWR_TXSSELN_ALL;
+ txtransfer.remaining = nwords;
+ rxtransfer.rxptr = (FAR uint8_t *)buffer;
+ rxtransfer.remaining = nwords;
+ rxtransfer.expected = 0;
+
+ /* Clear Tx/Rx errors and empty FIFOs */
+
+ lpc54_spi_resetfifos(priv);
+
+ /* Loop until all Tx data has been sent and until all Rx data has been
+ * received.
+ */
+
+ while (txtransfer.remaining != 0|| rxtransfer.remaining != 0)
+ {
+ /* Transfer one byte from the Rx FIFO to the caller's Rx buffer */
+
+ lpc54_spi_rxtransfer8(priv, &rxtransfer);
+
+ /* If sending another byte would exceed the capacity of the Rx FIFO
+ * then read-only until there space freed.
+ */
+
+ if (rxtransfer.expected < depth)
+ {
+ /* Attempt to transfer one dummy byte to the Tx FIFO. */
+
+ if (lpc54_spi_txdummy(priv, &txtransfer))
+ {
+ /* Increment the Rx expected count if successful */
+
+ rxtransfer.expected++;
+ }
+ }
+ }
+}
+
+#ifdef CONFIG_LPC54_SPI_WIDEDATA
+static void lpc54_spi_recvblock16(FAR struct lpc54_spidev_s *priv,
+ FAR void *buffer, size_t nwords)
+{
+ struct lpc54_rxtransfer16_s rxtransfer;
+ struct lpc54_txdummy_s txtransfer;
+ unsigned int depth;
+
+ DEBUGASSERT(buffer != NULL);
+
+ /* Get the FIFO depth */
+
+ depth = lpc54_spi_fifodepth(priv);
+
+ /* Set up the transfer data */
+
+ txtransfer.txctrl = SPI_DUMMYDATA16 | SPI_FIFOWR_LEN(priv->nbits) |
+ SPI_FIFOWR_TXSSELN_ALL;
+ txtransfer.remaining = nwords;
+ rxtransfer.rxptr = (FAR uint16_t *)rxbuffer;
+ rxtransfer.remaining = nwords;
+ rxtransfer.expected = 0;
+
+ /* Clear Tx/Rx errors and empty FIFOs */
+
+ lpc54_spi_resetfifos(priv);
+
+ /* Loop until all Tx data has been sent and until all Rx data has been
+ * received.
+ */
+
+ while (txtransfer.remaining || rxtransfer.remaining || rxtransfer.expected)
+ {
+ /* Transfer one HWord from the Rx FIFO to the caller's Rx buffer */
+
+ lpc54_spi_rxtransfer16(priv, &rxtransfer);
+
+ /* If sending another byte would exceed the capacity of the Rx FIFO
+ * then read-only until there space freed.
+ */
+
+ if (rxtransfer.expected < depth)
+ {
+ /* Attempt to transfer one dummy HWord to the Tx FIFO. */
+
+ if (lpc54_spi_txdummy(priv, &txtransfer))
+ {
+ /* Increment the Rx expected count if successful */
+
+ rxtransfer.expected++;
+ }
+ }
+ }
+}
+#endif /* CONFIG_LPC54_SPI_WIDEDATA */
+
/****************************************************************************
* Name: lpc54_spi_lock
*
* Description:
- * On SPI busses where there are multiple devices, it will be necessary to
- * lock SPI to have exclusive access to the busses for a sequence of
+ * On SPI buses where there are multiple devices, it will be necessary to
+ * lock SPI to have exclusive access to the buses for a sequence of
* transfers. The bus should be locked before the chip is selected. After
* locking the SPI bus, the caller should then also call the setfrequency,
* setbits, and setmode methods to make sure that the SPI is properly
@@ -303,11 +1308,15 @@ static uint32_t lpc54_spi_setfrequency(FAR struct spi_dev_s *dev,
uint32_t frequency)
{
FAR struct lpc54_spidev_s *priv = (FAR struct lpc54_spidev_s *)dev;
+ uint32_t divider;
uint32_t actual;
+ uint32_t regval;
- /* Check if the requested frequence is the same as the frequency selection */
+ /* Check if the requested frequency is the same as the current frequency
+ * selection.
+ */
- DEBUGASSERT(priv && frequency <= priv->fclock / 2);
+ DEBUGASSERT(priv != NULL && frequency <= priv->fclock / 2);
if (priv->frequency == frequency)
{
@@ -317,7 +1326,21 @@ static uint32_t lpc54_spi_setfrequency(FAR struct spi_dev_s *dev,
}
/* Set the new SPI frequency */
-#warning Missing logic
+
+ divider = priv->fclock / frequency;
+ if (divider > 0x10000)
+ {
+ divider = 0x10000;
+ }
+
+ regval = lpc54_spi_getreg(priv, LPC54_SPI_DIV_OFFSET);
+ regval &= ~SPI_DIV_MASK;
+ regval |= SPI_DIV(divider);
+ lpc54_spi_putreg(priv, LPC54_SPI_DIV_OFFSET, regval);
+
+ /* Calculate the actual frequency */
+
+ actual = priv->fclock / divider;
/* Save the frequency setting */
@@ -354,24 +1377,25 @@ static void lpc54_spi_setmode(FAR struct spi_dev_s *dev,
if (mode != priv->mode)
{
/* Yes... Set the new mode */
-#warning Missing logic
+
+ regval = lpc54_spi_getreg(priv, LPC54_SPI_CFG_OFFSET);
+ regval &= ~(SPI_CFG_CPHA | SPI_CFG_CPOL);
switch (mode)
{
case SPIDEV_MODE0: /* CPOL=0; CPHA=0 */
-#warning Missing logic
break;
case SPIDEV_MODE1: /* CPOL=0; CPHA=1 */
-#warning Missing logic
+ regval |= SPI_CFG_CPHA;
break;
case SPIDEV_MODE2: /* CPOL=1; CPHA=0 */
-#warning Missing logic
+ regval |= SPI_CFG_CPOL;
break;
case SPIDEV_MODE3: /* CPOL=1; CPHA=1 */
-#warning Missing logic
+ regval |= (SPI_CFG_CPHA | SPI_CFG_CPOL);
break;
default:
@@ -379,9 +1403,9 @@ static void lpc54_spi_setmode(FAR struct spi_dev_s *dev,
return;
}
-#warning Missing logic
+ lpc54_spi_putreg(priv, LPC54_SPI_CFG_OFFSET, regval);
- /* Save the mode so that subsequent re-configuratins will be faster */
+ /* Save the mode so that subsequent re-configurations will be faster */
priv->mode = mode;
}
@@ -405,18 +1429,14 @@ static void lpc54_spi_setmode(FAR struct spi_dev_s *dev,
static void lpc54_spi_setbits(FAR struct spi_dev_s *dev, int nbits)
{
FAR struct lpc54_spidev_s *priv = (FAR struct lpc54_spidev_s *)dev;
- uint32_t regval;
- /* Has the number of bits changed? */
+ /* The valid range of bit selections is SPI_MINWIDTH through SPI_MAXWIDTH */
- DEBUGASSERT(priv && nbits > 7 && nbits < 17);
+ DEBUGASSERT(priv != NULL && nbits >= SPI_MINWIDTH && nbits <= SPI_MAXWIDTH);
- if (nbits != priv->nbits)
+ if (nbits >= SPI_MINWIDTH && nbits <= SPI_MAXWIDTH)
{
- /* Yes... Set the number word width */
-#warning Missing logic
-
- /* Save the selection so the subsequence re-configurations will be faster */
+ /* Save the selection. It will be applied when data is transferred. */
priv->nbits = nbits;
}
@@ -440,28 +1460,46 @@ static void lpc54_spi_setbits(FAR struct spi_dev_s *dev, int nbits)
static uint16_t lpc54_spi_send(FAR struct spi_dev_s *dev, uint16_t wd)
{
- uint16_t ret;
+ FAR struct lpc54_spidev_s *priv = (FAR struct lpc54_spidev_s *)dev;
+ uint32_t regval;
- /* Write the data to transmitted to the SPI Data Register */
-#warning Missing logic
+ DEBUGASSERT(priv != NULL);
- /* Read the SPI Status Register again to clear the status bit */
-#warning Missing logic
+ /* Clear Tx/Rx errors and empty FIFOs */
- return ret;
+ lpc54_spi_resetfifos(priv);
+
+ /* Send the word. Since we just reset the FIFOs, we assume that the Tx
+ * FIFO is not full and that the Rx FIFO is empty.
+ */
+
+ DEBUGASSERT(lpc54_spi_txavailable(priv) || !lpc54_spi_rxavailable(priv));
+
+ regval = wd | SPI_FIFOWR_LEN(priv->nbits) | SPI_FIFOWR_TXSSELN_ALL;
+ lpc54_spi_putreg(priv, LPC54_SPI_FIFOWR_OFFSET, regval);
+
+ /* Wait for the Rx FIFO to become non-empty. */
+
+ while (!lpc54_spi_rxavailable(priv))
+ {
+ }
+
+ /* Then read and return the value from the Rx FIFO */
+
+ return (uint16_t)lpc54_spi_getreg(priv, LPC54_SPI_FIFORD_OFFSET);
}
/****************************************************************************
- * Name: lpc54_spi_exchange (no DMA). aka lpc54_spi_exchange_nodma
+ * Name: lpc54_spi_exchange
*
* Description:
- * Exchange a block of data on SPI without using DMA
+ * Exchange a block of data on SPI
*
* Input Parameters:
* dev - Device-specific state data
* txbuffer - A pointer to the buffer of data to be sent
* rxbuffer - A pointer to a buffer in which to receive data
- * nwords - the length of data to be exchaned in units of words.
+ * nwords - the length of data to be exchanged in units of words.
* The wordsize is determined by the number of bits-per-word
* selected for the SPI interface. If nbits <= 8, the data is
* packed into uint8_t's; if nbits >8, the data is packed into
@@ -472,125 +1510,52 @@ static uint16_t lpc54_spi_send(FAR struct spi_dev_s *dev, uint16_t wd)
*
****************************************************************************/
-#ifndef CONFIG_LPC54_SPI_MASTER_DMA
-static void lpc54_spi_exchange(FAR struct spi_dev_s *dev,
+#ifdef CONFIG_SPI_EXCHANGE
+static void lpc54_spi_exchange(FAR struct lpc54_spidev_s *priv,
FAR const void *txbuffer, FAR void *rxbuffer,
size_t nwords)
-#else
-static void lpc54_spi_exchange_nodma(FAR struct spi_dev_s *dev,
- FAR const void *txbuffer,
- FAR void *rxbuffer, size_t nwords)
-#endif
{
FAR struct lpc54_spidev_s *priv = (FAR struct lpc54_spidev_s *)dev;
- DEBUGASSERT(priv && priv->base);
- spiinfo("txbuffer=%p rxbuffer=%p nwords=%d\n",
- txbuffer, rxbuffer, nwords);
+ DEBUGASSERT(priv != NULL);
- /* 8- or 16-bit mode? */
+ /* If there is no data sink, then handle this transfer with
+ * lpc54_spi_sndblock().
+ */
- if (lpc54_spi_16bitmode(priv))
+ if (rxbuffer == NULL)
{
- /* 16-bit mode */
-
- const uint16_t *src = (const uint16_t *)txbuffer;
- uint16_t *dest = (uint16_t *)rxbuffer;
- uint16_t word;
-
- while (nwords-- > 0)
- {
- /* Get the next word to write. Is there a source buffer? */
-
- if (src)
- {
- word = *src++;
- }
- else
- {
- word = 0xffff;
- }
-
- /* Exchange one word */
-
- word = spi_send(dev, word);
-
- /* Is there a buffer to receive the return value? */
-
- if (dest)
- {
- *dest++ = word;
- }
- }
+ lpc54_spi_sndblock(priv, txbuffer, nwords)
}
- else
+
+ /* If there is no data source, then handle this transfer with
+ * lpc54_spi_recvblock().
+ */
+
+ else if (txbuffer == NULL)
{
- /* 8-bit mode */
+ lpc54_spi_recvblock(priv, rxbuffer, nwords)
+ }
- const uint8_t *src = (const uint8_t *)txbuffer;
- uint8_t *dest = (uint8_t *)rxbuffer;
- uint8_t word;
+#ifdef CONFIG_LPC54_SPI_WIDEDATA
+ /* If the data with is > 8-bits, then handle this transfer with
+ * lpc54_spi_exchange16().
+ */
- while (nwords-- > 0)
- {
- /* Get the next word to write. Is there a source buffer? */
+ else if (priv->nbits > 8)
+ {
+ lpc54_spi_exchange16(priv, txbuffer, rxbuffer, nwords);
+ }
+#endif
- if (src)
- {
- word = *src++;
- }
- else
- {
- word = 0xff;
- }
+ /* Otherwise, let lpc54_spi_exchange8() do the job */
- /* Exchange one word */
-
- word = (uint8_t)spi_send(dev, (uint16_t)word);
-
- /* Is there a buffer to receive the return value? */
-
- if (dest)
- {
- *dest++ = word;
- }
- }
+ else if (priv->nbits > 8)
+ {
+ lpc54_spi_exchange8(priv, txbuffer, rxbuffer, nwords);
}
}
-
-/****************************************************************************
- * Name: lpc54_spi_exchange (no DMA). aka lpc54_spi_exchange_nodma
- *
- * Description:
- * Exchange a block of data on SPI without using DMA
- *
- * Input Parameters:
- * dev - Device-specific state data
- * txbuffer - A pointer to the buffer of data to be sent
- * rxbuffer - A pointer to a buffer in which to receive data
- * nwords - the length of data to be exchaned in units of words.
- * The wordsize is determined by the number of bits-per-word
- * selected for the SPI interface. If nbits <= 8, the data is
- * packed into uint8_t's; if nbits >8, the data is packed into
- * uint16_t's
- *
- * Returned Value:
- * None
- *
- ****************************************************************************/
-
-#ifdef CONFIG_LPC54_SPI_MASTER_DMA
-static void lpc54_spi_exchange(FAR struct spi_dev_s *dev,
- FAR const void *txbuffer, FAR void *rxbuffer,
- size_t nwords)
-{
- /* If the transfer is small, then perform the exchange without using DMA. */
-#warning Missing logic
-
- /* Otherwise, use DMA */
-#warning Missing logic
-}
-#endif /* CONFIG_LPC54_SPI_MASTER_DMA */
+#endif /* CONFIG_SPI_EXCHANGE */
/****************************************************************************
* Name: lpc54_spi_sndblock
@@ -615,8 +1580,28 @@ static void lpc54_spi_exchange(FAR struct spi_dev_s *dev,
static void lpc54_spi_sndblock(FAR struct spi_dev_s *dev,
FAR const void *buffer, size_t nwords)
{
- spiinfo("txbuffer=%p nwords=%d\n", txbuffer, nwords);
- return lpc54_spi_exchange(dev, txbuffer, NULL, nwords);
+ FAR struct lpc54_spidev_s *priv = (FAR struct lpc54_spidev_s *)dev;
+
+ spiinfo("buffer=%p nwords=%d\n", buffer, nwords);
+ DEBUGASSERT(priv != NULL && buffer != NULL);
+
+#ifdef CONFIG_LPC54_SPI_WIDEDATA
+ /* If the data with is > 8-bits, then handle this transfer with
+ * lpc54_spi_sndblock16().
+ */
+
+ if (priv->nbits > 8)
+ {
+ lpc54_spi_sndblock16(priv, buffer, nwords);
+ }
+
+ /* Otherwise, let lpc54_spi_sndblock8() do the job */
+
+ else if (priv->nbits > 8)
+#endif
+ {
+ lpc54_spi_sndblock8(priv, buffer, nwords);
+ }
}
/****************************************************************************
@@ -627,7 +1612,7 @@ static void lpc54_spi_sndblock(FAR struct spi_dev_s *dev,
*
* Input Parameters:
* dev - Device-specific state data
- * buffer - A pointer to the buffer in which to recieve data
+ * buffer - A pointer to the buffer in which to receive data
* nwords - the length of data that can be received in the buffer in
* number of words. The wordsize is determined by the number of
* bits-per-word selected for the SPI interface. If nbits <= 8,
@@ -642,8 +1627,28 @@ static void lpc54_spi_sndblock(FAR struct spi_dev_s *dev,
static void lpc54_spi_recvblock(FAR struct spi_dev_s *dev, FAR void *buffer,
size_t nwords)
{
- spiinfo("rxbuffer=%p nwords=%d\n", rxbuffer, nwords);
- return lpc54_spi_exchange(dev, NULL, rxbuffer, nwords);
+ FAR struct lpc54_spidev_s *priv = (FAR struct lpc54_spidev_s *)dev;
+
+ spiinfo("buffer=%p nwords=%d\n", buffer, nwords);
+ DEBUGASSERT(priv != NULL && buffer != NULL);
+
+#ifdef CONFIG_LPC54_SPI_WIDEDATA
+ /* If the data with is > 8-bits, then handle this transfer with
+ * lpc54_spi_recvblock16().
+ */
+
+ if (priv->nbits > 8)
+ {
+ lpc54_spi_recvblock16(priv, buffer, nwords);
+ }
+
+ /* Otherwise, let lpc54_spi_recvblock8() do the job */
+
+ else if (priv->nbits > 8)
+#endif
+ {
+ lpc54_spi_recvblock8(priv, buffer, nwords);
+ }
}
/****************************************************************************
@@ -672,15 +1677,16 @@ FAR struct spi_dev_s *lpc54_spibus_initialize(int port)
{
struct lpc54_spidev_s *priv;
irqstate_t flags;
+ uint32_t regval;
flags = enter_critical_section();
- /* Configure the requestin SPI peripheral */
+ /* Configure the requested SPI peripheral */
/* NOTE: The basic FLEXCOMM initialization was performed in
* lpc54_lowputc.c.
*/
-#ifdef CONFIG_LPC54_I2C0_MASTER
+#ifdef CONFIG_LPC54_SPI0_MASTER
if (port == 0)
{
/* Attach 12 MHz clock to FLEXCOMM0 */
@@ -698,14 +1704,15 @@ FAR struct spi_dev_s *lpc54_spibus_initialize(int port)
priv = &g_spi0_dev;
priv->base = LPC54_FLEXCOMM0_BASE;
- priv->irqid = LPC54_IRQ_FLEXCOMM0;
+ priv->irq = LPC54_IRQ_FLEXCOMM0;
priv->fclock = BOARD_FLEXCOMM0_FCLK;
+ priv->dev.ops = &g_spi0_ops;
/* Configure SPI pins (defined in board.h) */
- lpc54_gpio_config(GPIO_I2C0_SCK);
- lpc54_gpio_config(GPIO_I2C0_MOSI);
- lpc54_gpio_config(GPIO_I2C0_MISO);
+ lpc54_gpio_config(GPIO_SPI0_SCK);
+ lpc54_gpio_config(GPIO_SPI0_MOSI);
+ lpc54_gpio_config(GPIO_SPI0_MISO);
/* Set up the FLEXCOMM0 function clock */
@@ -713,7 +1720,7 @@ FAR struct spi_dev_s *lpc54_spibus_initialize(int port)
}
else
#endif
-#ifdef CONFIG_LPC54_I2C1_MASTER
+#ifdef CONFIG_LPC54_SPI1_MASTER
if (port == 1)
{
/* Attach 12 MHz clock to FLEXCOMM1 */
@@ -731,14 +1738,15 @@ FAR struct spi_dev_s *lpc54_spibus_initialize(int port)
priv = &g_spi1_dev;
priv->base = LPC54_FLEXCOMM1_BASE;
- priv->irqid = LPC54_IRQ_FLEXCOMM1;
+ priv->irq = LPC54_IRQ_FLEXCOMM1;
priv->fclock = BOARD_FLEXCOMM1_FCLK;
+ priv->dev.ops = &g_spi1_ops;
/* Configure SPI pins (defined in board.h) */
- lpc54_gpio_config(GPIO_I2C1_SCK);
- lpc54_gpio_config(GPIO_I2C1_MOSI);
- lpc54_gpio_config(GPIO_I2C1_MISO);
+ lpc54_gpio_config(GPIO_SPI1_SCK);
+ lpc54_gpio_config(GPIO_SPI1_MOSI);
+ lpc54_gpio_config(GPIO_SPI1_MISO);
/* Set up the FLEXCOMM1 function clock */
@@ -746,7 +1754,7 @@ FAR struct spi_dev_s *lpc54_spibus_initialize(int port)
}
else
#endif
-#ifdef CONFIG_LPC54_I2C2_MASTER
+#ifdef CONFIG_LPC54_SPI2_MASTER
if (port == 2)
{
/* Attach 12 MHz clock to FLEXCOMM2 */
@@ -764,14 +1772,15 @@ FAR struct spi_dev_s *lpc54_spibus_initialize(int port)
priv = &g_spi2_dev;
priv->base = LPC54_FLEXCOMM2_BASE;
- priv->irqid = LPC54_IRQ_FLEXCOMM2;
+ priv->irq = LPC54_IRQ_FLEXCOMM2;
priv->fclock = BOARD_FLEXCOMM2_FCLK;
+ priv->dev.ops = &g_spi2_ops;
/* Configure SPI pins (defined in board.h) */
- lpc54_gpio_config(GPIO_I2C2_SCK);
- lpc54_gpio_config(GPIO_I2C2_MOSI);
- lpc54_gpio_config(GPIO_I2C2MISO);
+ lpc54_gpio_config(GPIO_SPI2_SCK);
+ lpc54_gpio_config(GPIO_SPI2_MOSI);
+ lpc54_gpio_config(GPIO_SPI2MISO);
/* Set up the FLEXCOMM2 function clock */
@@ -779,7 +1788,7 @@ FAR struct spi_dev_s *lpc54_spibus_initialize(int port)
}
else
#endif
-#ifdef CONFIG_LPC54_I2C3_MASTER
+#ifdef CONFIG_LPC54_SPI3_MASTER
if (port == 3)
{
/* Attach 12 MHz clock to FLEXCOMM3 */
@@ -797,14 +1806,15 @@ FAR struct spi_dev_s *lpc54_spibus_initialize(int port)
priv = &g_spi3_dev;
priv->base = LPC54_FLEXCOMM3_BASE;
- priv->irqid = LPC54_IRQ_FLEXCOMM3;
+ priv->irq = LPC54_IRQ_FLEXCOMM3;
priv->fclock = BOARD_FLEXCOMM3_FCLK;
+ priv->dev.ops = &g_spi3_ops;
/* Configure SPI pins (defined in board.h) */
- lpc54_gpio_config(GPIO_I2C3_SCK);
- lpc54_gpio_config(GPIO_I2C3_MOSI);
- lpc54_gpio_config(GPIO_I2C3_MISO);
+ lpc54_gpio_config(GPIO_SPI3_SCK);
+ lpc54_gpio_config(GPIO_SPI3_MOSI);
+ lpc54_gpio_config(GPIO_SPI3_MISO);
/* Set up the FLEXCOMM3 function clock */
@@ -812,7 +1822,7 @@ FAR struct spi_dev_s *lpc54_spibus_initialize(int port)
}
else
#endif
-#ifdef CONFIG_LPC54_I2C4_MASTER
+#ifdef CONFIG_LPC54_SPI4_MASTER
if (port == 4)
{
/* Attach 12 MHz clock to FLEXCOMM4 */
@@ -830,14 +1840,15 @@ FAR struct spi_dev_s *lpc54_spibus_initialize(int port)
priv = &g_spi4_dev;
priv->base = LPC54_FLEXCOMM4_BASE;
- priv->irqid = LPC54_IRQ_FLEXCOMM4;
+ priv->irq = LPC54_IRQ_FLEXCOMM4;
priv->fclock = BOARD_FLEXCOMM4_FCLK;
+ priv->dev.ops = &g_spi4_ops;
/* Configure SPI pins (defined in board.h) */
- lpc54_gpio_config(GPIO_I2C4_SCK);
- lpc54_gpio_config(GPIO_I2C4_MOSI);
- lpc54_gpio_config(GPIO_I2C4_MISO);
+ lpc54_gpio_config(GPIO_SPI4_SCK);
+ lpc54_gpio_config(GPIO_SPI4_MOSI);
+ lpc54_gpio_config(GPIO_SPI4_MISO);
/* Set up the FLEXCOMM4 function clock */
@@ -845,7 +1856,7 @@ FAR struct spi_dev_s *lpc54_spibus_initialize(int port)
}
else
#endif
-#ifdef CONFIG_LPC54_I2C5_MASTER
+#ifdef CONFIG_LPC54_SPI5_MASTER
if (port == 5)
{
/* Attach 12 MHz clock to FLEXCOMM5 */
@@ -863,14 +1874,15 @@ FAR struct spi_dev_s *lpc54_spibus_initialize(int port)
priv = &g_spi5_dev;
priv->base = LPC54_FLEXCOMM5_BASE;
- priv->irqid = LPC54_IRQ_FLEXCOMM5;
+ priv->irq = LPC54_IRQ_FLEXCOMM5;
priv->fclock = BOARD_FLEXCOMM5_FCLK;
+ priv->dev.ops = &g_spi5_ops;
/* Configure SPI pins (defined in board.h) */
- lpc54_gpio_config(GPIO_I2C5_SCK);
- lpc54_gpio_config(GPIO_I2C5_MOSI);
- lpc54_gpio_config(GPIO_I2C5_MISO);
+ lpc54_gpio_config(GPIO_SPI5_SCK);
+ lpc54_gpio_config(GPIO_SPI5_MOSI);
+ lpc54_gpio_config(GPIO_SPI5_MISO);
/* Set up the FLEXCOMM5 function clock */
@@ -878,7 +1890,7 @@ FAR struct spi_dev_s *lpc54_spibus_initialize(int port)
}
else
#endif
-#ifdef CONFIG_LPC54_I2C6_MASTER
+#ifdef CONFIG_LPC54_SPI6_MASTER
if (port == 6)
{
/* Attach 12 MHz clock to FLEXCOMM6 */
@@ -896,14 +1908,15 @@ FAR struct spi_dev_s *lpc54_spibus_initialize(int port)
priv = &g_spi6_dev;
priv->base = LPC54_FLEXCOMM6_BASE;
- priv->irqid = LPC54_IRQ_FLEXCOMM6;
+ priv->irq = LPC54_IRQ_FLEXCOMM6;
priv->fclock = BOARD_FLEXCOMM6_FCLK;
+ priv->dev.ops = &g_spi6_ops;
/* Configure SPI pins (defined in board.h) */
- lpc54_gpio_config(GPIO_I2C6_SCK);
- lpc54_gpio_config(GPIO_I2C6_MOSI);
- lpc54_gpio_config(GPIO_I2C6_MISO);
+ lpc54_gpio_config(GPIO_SPI6_SCK);
+ lpc54_gpio_config(GPIO_SPI6_MOSI);
+ lpc54_gpio_config(GPIO_SPI6_MISO);
/* Set up the FLEXCOMM6 function clock */
@@ -911,7 +1924,7 @@ FAR struct spi_dev_s *lpc54_spibus_initialize(int port)
}
else
#endif
-#ifdef CONFIG_LPC54_I2C7_MASTER
+#ifdef CONFIG_LPC54_SPI7_MASTER
if (port == 7)
{
/* Attach 12 MHz clock to FLEXCOMM7 */
@@ -929,14 +1942,15 @@ FAR struct spi_dev_s *lpc54_spibus_initialize(int port)
priv = &g_spi7_dev;
priv->base = LPC54_FLEXCOMM7_BASE;
- priv->irqid = LPC54_IRQ_FLEXCOMM7;
+ priv->irq = LPC54_IRQ_FLEXCOMM7;
priv->fclock = BOARD_FLEXCOMM7_FCLK;
+ priv->dev.ops = &g_spi7_ops;
/* Configure SPI pins (defined in board.h) */
- lpc54_gpio_config(GPIO_I2C7_SCK);
- lpc54_gpio_config(GPIO_I2C7_MOSI);
- lpc54_gpio_config(GPIO_I2C7_MISO);
+ lpc54_gpio_config(GPIO_SPI7_SCK);
+ lpc54_gpio_config(GPIO_SPI7_MOSI);
+ lpc54_gpio_config(GPIO_SPI7_MISO);
/* Set up the FLEXCOMM7 function clock */
@@ -944,7 +1958,7 @@ FAR struct spi_dev_s *lpc54_spibus_initialize(int port)
}
else
#endif
-#ifdef CONFIG_LPC54_I2C8_MASTER
+#ifdef CONFIG_LPC54_SPI8_MASTER
if (port == 8)
{
/* Attach 12 MHz clock to FLEXCOMM8 */
@@ -962,14 +1976,15 @@ FAR struct spi_dev_s *lpc54_spibus_initialize(int port)
priv = &g_spi8_dev;
priv->base = LPC54_FLEXCOMM8_BASE;
- priv->irqid = LPC54_IRQ_FLEXCOMM8;
+ priv->irq = LPC54_IRQ_FLEXCOMM8;
priv->fclock = BOARD_FLEXCOMM8_FCLK;
+ priv->dev.ops = &g_spi8_ops;
/* Configure SPI pins (defined in board.h) */
- lpc54_gpio_config(GPIO_I2C8_SCK);
- lpc54_gpio_config(GPIO_I2C8_MOSI);
- lpc54_gpio_config(GPIO_I2C8_MISO);
+ lpc54_gpio_config(GPIO_SPI8_SCK);
+ lpc54_gpio_config(GPIO_SPI8_MOSI);
+ lpc54_gpio_config(GPIO_SPI8_MISO);
/* Set up the FLEXCOMM8 function clock */
@@ -977,7 +1992,7 @@ FAR struct spi_dev_s *lpc54_spibus_initialize(int port)
}
else
#endif
-#ifdef CONFIG_LPC54_I2C9_MASTER
+#ifdef CONFIG_LPC54_SPI9_MASTER
if (port == 9)
{
/* Attach 12 MHz clock to FLEXCOMM9 */
@@ -995,14 +2010,15 @@ FAR struct spi_dev_s *lpc54_spibus_initialize(int port)
priv = &g_spi9_dev;
priv->base = LPC54_FLEXCOMM9_BASE;
- priv->irqid = LPC54_IRQ_FLEXCOMM9;
+ priv->irq = LPC54_IRQ_FLEXCOMM9;
priv->fclock = BOARD_FLEXCOMM9_FCLK;
+ priv->dev.ops = &g_spi9_ops;
/* Configure SPI pins (defined in board.h) */
- lpc54_gpio_config(GPIO_I2C9_SCK);
- lpc54_gpio_config(GPIO_I2C9_MOSI);
- lpc54_gpio_config(GPIO_I2C9_MISO);
+ lpc54_gpio_config(GPIO_SPI9_SCK);
+ lpc54_gpio_config(GPIO_SPI9_MOSI);
+ lpc54_gpio_config(GPIO_SPI9_MISO);
/* Set up the FLEXCOMM9 function clock */
@@ -1016,24 +2032,69 @@ FAR struct spi_dev_s *lpc54_spibus_initialize(int port)
leave_critical_section(flags);
- /* Enable the SPI peripheral*/
- /* Configure 8-bit SPI mode and master mode */
-#warning Missing logic
-
/* Set the initial SPI configuration */
priv->frequency = 0;
priv->nbits = 8;
priv->mode = SPIDEV_MODE0;
- priv->dev.ops = &g_spi_ops;
+
+ /* Initialize the SPI semaphore that enforces mutually exclusive access */
+
+ nxsem_init(&priv->exclsem, 0, 1);
+
+ /* Configure master mode in mode 0:
+ *
+ * ENABLE - Disabled for now (0)
+ * MASTER - Master mode (1)
+ * LSBF - MSB first (0)
+ * CPHA/CPOL - Mode 0 (0,0)
+ * LOOP - Disable loopback mode (0)
+ * SPOLn - Active low (0,0,0)
+ */
+
+ regval = lpc54_spi_getreg(priv, LPC54_SPI_CFG_OFFSET);
+ regval &= ~(SPI_CFG_ENABLE | SPI_CFG_LSBF | SPI_CFG_CPHA | SPI_CFG_CPOL |
+ SPI_CFG_LOOP | SPI_CFG_SPOL0 | SPI_CFG_SPOL1 | SPI_CFG_SPOL2 |
+ SPI_CFG_SPOL3);
+ regval |= SPI_CFG_MASTER;
+ lpc54_spi_putreg(priv, LPC54_SPI_CFG_OFFSET, regval);
+
+ /* Enable FIFOs */
+
+ regval = lpc54_spi_getreg(priv, LPC54_SPI_FIFOCFG_OFFSET);
+ regval |= (SPI_FIFOCFG_EMPTYTX | SPI_FIFOCFG_EMPTYRX);
+ lpc54_spi_putreg(priv, LPC54_SPI_FIFOCFG_OFFSET, regval);
+
+ regval |= (SPI_FIFOCFG_ENABLETX | SPI_FIFOCFG_ENABLERX);
+ lpc54_spi_putreg(priv, LPC54_SPI_FIFOCFG_OFFSET, regval);
+
+ /* Set FIFO trigger levels: Empty for Tx FIFO; 1 word for RxFIFO */
+
+ regval = lpc54_spi_getreg(priv, LPC54_SPI_FIFOCFG_OFFSET);
+ regval &= ~(SPI_FIFOTRIG_TXLVL_MASK | SPI_FIFOTRIG_RXLVL_MASK);
+ regval |= (SPI_FIFOTRIG_TXLVL_EMPTY | SPI_FIFOTRIG_RXLVL_NOTEMPTY);
+
+ /* Enable generation of interrupts for selected FIFO trigger levels */
+
+ regval |= (SPI_FIFOTRIG_TXLVLENA | SPI_FIFOTRIG_RXLVLENA);
+ lpc54_spi_putreg(priv, LPC54_SPI_FIFOCFG_OFFSET, regval);
+
+ /* Set the delay configuration (not used) */
+
+ regval = (SPI_DLY_PRE_DELAY(0) | SPI_DLY_POST_DELAY(0) | SPI_DLY_FRAME_DELAY(0) |
+ SPI_DLY_TRANSFER_DELAY(0));
+ lpc54_spi_putreg(priv, LPC54_SPI_DLY_OFFSET, regval);
/* Select a default frequency of approx. 400KHz */
lpc54_spi_setfrequency((FAR struct spi_dev_s *)priv, 400000);
- /* Initialize the SPI semaphore that enforces mutually exclusive access */
+ /* Enable the SPI peripheral */
+
+ regval = lpc54_spi_getreg(priv, LPC54_SPI_CFG_OFFSET);
+ regval |= SPI_CFG_ENABLE;
+ lpc54_spi_putreg(priv, LPC54_SPI_CFG_OFFSET, regval);
- nxsem_init(&priv->exclsem, 0, 1);
return &priv->dev;
}
diff --git a/arch/arm/src/lpc54xx/lpc54_spi_master.h b/arch/arm/src/lpc54xx/lpc54_spi_master.h
index 376c3a6e768..aba9a30e72d 100644
--- a/arch/arm/src/lpc54xx/lpc54_spi_master.h
+++ b/arch/arm/src/lpc54xx/lpc54_spi_master.h
@@ -109,45 +109,111 @@ extern "C"
FAR struct spi_dev_s *lpc54_spibus_initialize(int port);
/************************************************************************************
- * Name: lpc54_spiselect, lpc54_spistatus, and lpc54_spicmddata
+ * Name: lpc54_spiN_select, lpc54_spiN_status, and lpc54_spiN_cmddata
*
* Description:
* These functions must be provided in your board-specific logic. The
- * lpc54_spiselect function will perform chip selection and the lpc54_spistatus
+ * lpc54_spiN_select function will perform chip selection and the lpc54_spiN_status
* will perform status operations using GPIOs in the way your board is configured.
*
* If CONFIG_SPI_CMDDATA is defined in the NuttX configuration, then
- * lpc54_spicmddata must also be provided. This functions performs cmd/data
+ * lpc54_spiN_cmddata must also be provided. This functions performs cmd/data
* selection operations using GPIOs in the way your board is configured.
*
************************************************************************************/
-void lpc54_spiselect(FAR struct spi_dev_s *dev, uint32_t devid, bool selected);
-uint8_t lpc54_spistatus(FAR struct spi_dev_s *dev, uint32_t devid);
+#ifdef CONFIG_LPC54_SPI0_MASTER
+void lpc54_spi0_select(FAR struct spi_dev_s *dev, uint32_t devid, bool selected);
+uint8_t lpc54_spi0_status(FAR struct spi_dev_s *dev, uint32_t devid);
#ifdef CONFIG_SPI_CMDDATA
-int lpc54_spicmddata(FAR struct spi_dev_s *dev, uint32_t devid, bool cmd);
+int lpc54_spi0_cmddata(FAR struct spi_dev_s *dev, uint32_t devid, bool cmd);
+#endif
+#endif
+
+#ifdef CONFIG_LPC54_SPI1_MASTER
+void lpc54_spi1_select(FAR struct spi_dev_s *dev, uint32_t devid, bool selected);
+uint8_t lpc54_spi1_status(FAR struct spi_dev_s *dev, uint32_t devid);
+
+#ifdef CONFIG_SPI_CMDDATA
+int lpc54_spi1_cmddata(FAR struct spi_dev_s *dev, uint32_t devid, bool cmd);
+#endif
+#endif
+
+#ifdef CONFIG_LPC54_SPI2_MASTER
+void lpc54_spi2_select(FAR struct spi_dev_s *dev, uint32_t devid, bool selected);
+uint8_t lpc54_spi2_status(FAR struct spi_dev_s *dev, uint32_t devid);
+
+#ifdef CONFIG_SPI_CMDDATA
+int lpc54_spi2_cmddata(FAR struct spi_dev_s *dev, uint32_t devid, bool cmd);
+#endif
+#endif
+
+#ifdef CONFIG_LPC54_SPI3_MASTER
+void lpc54_spi3_select(FAR struct spi_dev_s *dev, uint32_t devid, bool selected);
+uint8_t lpc54_spi3_status(FAR struct spi_dev_s *dev, uint32_t devid);
+
+#ifdef CONFIG_SPI_CMDDATA
+int lpc54_spi3_cmddata(FAR struct spi_dev_s *dev, uint32_t devid, bool cmd);
+#endif
+#endif
+
+#ifdef CONFIG_LPC54_SPI4_MASTER
+void lpc54_spi4_select(FAR struct spi_dev_s *dev, uint32_t devid, bool selected);
+uint8_t lpc54_spi4_status(FAR struct spi_dev_s *dev, uint32_t devid);
+
+#ifdef CONFIG_SPI_CMDDATA
+int lpc54_spi4_cmddata(FAR struct spi_dev_s *dev, uint32_t devid, bool cmd);
+#endif
+#endif
+
+#ifdef CONFIG_LPC54_SPI5_MASTER
+void lpc54_spi5_select(FAR struct spi_dev_s *dev, uint32_t devid, bool selected);
+uint8_t lpc54_spi5_status(FAR struct spi_dev_s *dev, uint32_t devid);
+
+#ifdef CONFIG_SPI_CMDDATA
+int lpc54_spi5_cmddata(FAR struct spi_dev_s *dev, uint32_t devid, bool cmd);
+#endif
+#endif
+
+#ifdef CONFIG_LPC54_SPI6_MASTER
+void lpc54_spi6_select(FAR struct spi_dev_s *dev, uint32_t devid, bool selected);
+uint8_t lpc54_spi6_status(FAR struct spi_dev_s *dev, uint32_t devid);
+
+#ifdef CONFIG_SPI_CMDDATA
+int lpc54_spi6_cmddata(FAR struct spi_dev_s *dev, uint32_t devid, bool cmd);
+#endif
+#endif
+
+#ifdef CONFIG_LPC54_SPI7_MASTER
+void lpc54_spi7_select(FAR struct spi_dev_s *dev, uint32_t devid, bool selected);
+uint8_t lpc54_spi7_status(FAR struct spi_dev_s *dev, uint32_t devid);
+
+#ifdef CONFIG_SPI_CMDDATA
+int lpc54_spi7_cmddata(FAR struct spi_dev_s *dev, uint32_t devid, bool cmd);
+#endif
+#endif
+
+#ifdef CONFIG_LPC54_SPI8_MASTER
+void lpc54_spi8_select(FAR struct spi_dev_s *dev, uint32_t devid, bool selected);
+uint8_t lpc54_spi8_status(FAR struct spi_dev_s *dev, uint32_t devid);
+
+#ifdef CONFIG_SPI_CMDDATA
+int lpc54_spi8_cmddata(FAR struct spi_dev_s *dev, uint32_t devid, bool cmd);
+#endif
+#endif
+
+#ifdef CONFIG_LPC54_SPI9_MASTER
+void lpc54_spi9_select(FAR struct spi_dev_s *dev, uint32_t devid, bool selected);
+uint8_t lpc54_spi9_status(FAR struct spi_dev_s *dev, uint32_t devid);
+
+#ifdef CONFIG_SPI_CMDDATA
+int lpc54_spi9_cmddata(FAR struct spi_dev_s *dev, uint32_t devid, bool cmd);
+#endif
#endif
/************************************************************************************
- * Name: spi_flush
- *
- * Description:
- * Flush and discard any words left in the RX fifo. This can be called from
- * spiselect after a device is deselected (if you worry about such things).
- *
- * Input Parameters:
- * dev - Device-specific state data
- *
- * Returned Value:
- * None
- *
- ************************************************************************************/
-
-void spi_flush(FAR struct spi_dev_s *dev);
-
-/************************************************************************************
- * Name: lpc54_spi/spiregister
+ * Name: lpc54_spiN_register
*
* Description:
* If the board supports a card detect callback to inform the SPI-based MMC/SD
@@ -167,8 +233,37 @@ void spi_flush(FAR struct spi_dev_s *dev);
************************************************************************************/
#ifdef CONFIG_SPI_CALLBACK
-int lpc54_spiregister(FAR struct spi_dev_s *dev, spi_mediachange_t callback, void *arg);
+#ifdef CONFIG_LPC54_SPI0_MASTER
+int lpc54_spi0_register(FAR struct spi_dev_s *dev, spi_mediachange_t callback, void *arg);
#endif
+#ifdef CONFIG_LPC54_SPI1_MASTER
+int lpc54_spi1_register(FAR struct spi_dev_s *dev, spi_mediachange_t callback, void *arg);
+#endif
+#ifdef CONFIG_LPC54_SPI2_MASTER
+int lpc54_spi2_register(FAR struct spi_dev_s *dev, spi_mediachange_t callback, void *arg);
+#endif
+#ifdef CONFIG_LPC54_SPI3_MASTER
+int lpc54_spi3_register(FAR struct spi_dev_s *dev, spi_mediachange_t callback, void *arg);
+#endif
+#ifdef CONFIG_LPC54_SPI4_MASTER
+int lpc54_spi4_register(FAR struct spi_dev_s *dev, spi_mediachange_t callback, void *arg);
+#endif
+#ifdef CONFIG_LPC54_SPI5_MASTER
+int lpc54_spi5_register(FAR struct spi_dev_s *dev, spi_mediachange_t callback, void *arg);
+#endif
+#ifdef CONFIG_LPC54_SPI6_MASTER
+int lpc54_spi6_register(FAR struct spi_dev_s *dev, spi_mediachange_t callback, void *arg);
+#endif
+#ifdef CONFIG_LPC54_SPI7_MASTER
+int lpc54_spi7_register(FAR struct spi_dev_s *dev, spi_mediachange_t callback, void *arg);
+#endif
+#ifdef CONFIG_LPC54_SPI8_MASTER
+int lpc54_spi8_register(FAR struct spi_dev_s *dev, spi_mediachange_t callback, void *arg);
+#endif
+#ifdef CONFIG_LPC54_SPI9_MASTER
+int lpc54_spi9_register(FAR struct spi_dev_s *dev, spi_mediachange_t callback, void *arg);
+#endif
+#endif /* CONFIG_SPI_CALLBACK */
#undef EXTERN
#if defined(__cplusplus)
diff --git a/arch/arm/src/stm32/chip/stm32f33xxx_hrtim.h b/arch/arm/src/stm32/chip/stm32f33xxx_hrtim.h
index 0e962104f91..32dff07659b 100644
--- a/arch/arm/src/stm32/chip/stm32f33xxx_hrtim.h
+++ b/arch/arm/src/stm32/chip/stm32f33xxx_hrtim.h
@@ -447,8 +447,8 @@
# define HRTIM_TIMDT_DTPRSC_110 (6 << HRTIM_TIMDT_DTPRSC_SHIFT)
# define HRTIM_TIMDT_DTPRSC_111 (7 << HRTIM_TIMDT_DTPRSC_SHIFT)
#define HRTIM_TIMDT_DTRSLK (1 << 14) /* Bit 14: Deadtime Rising Sign Lock */
-#define HRTIM_TIMDT_DTRLK (1 << 14) /* Bit 15: Deadtime Rising Lock */
-#define HRTIM_TIMDT_DTF_SHIFT 0 /* Bits 16-24: Deadtime Falling Value */
+#define HRTIM_TIMDT_DTRLK (1 << 15) /* Bit 15: Deadtime Rising Lock */
+#define HRTIM_TIMDT_DTF_SHIFT 16 /* Bits 16-24: Deadtime Falling Value */
#define HRTIM_TIMDT_DTF_MASK (0x1ff << HRTIM_TIMDT_DTF_SHIFT)
#define HRTIM_TIMDT_SDTF (1 << 25) /* Bit 25: Sign Deadtime Falling Value */
#define HRTIM_TIMDT_DTFSLK (1 << 30) /* Bit 30: Deadtime Falling Sign Lock */
diff --git a/arch/arm/src/stm32/stm32_hrtim.c b/arch/arm/src/stm32/stm32_hrtim.c
index d064c8e1d3b..44f78bff6f6 100644
--- a/arch/arm/src/stm32/stm32_hrtim.c
+++ b/arch/arm/src/stm32/stm32_hrtim.c
@@ -317,10 +317,11 @@ struct stm32_hrtim_chopper_s
#ifdef CONFIG_STM32_HRTIM_DEADTIME
struct stm32_hrtim_deadtime_s
{
+ uint8_t en:1; /* Enable deadtime for timer */
uint8_t fsign_lock:1; /* Deadtime falling sing lock */
uint8_t rsign_lock:1; /* Deadtime rising sing lock */
- uint8_t rising_lock:1; /* Deadtime rising value lock */
uint8_t falling_lock:1; /* Deadtime falling value lock */
+ uint8_t rising_lock:1; /* Deadtime rising value lock */
uint8_t fsign:1; /* Deadtime falling sign */
uint8_t rsign:1; /* Deadtime rising sign */
uint8_t prescaler:3; /* Deadtime prescaler */
@@ -645,6 +646,10 @@ static int hrtim_synch_config(FAR struct stm32_hrtim_s *priv);
static int hrtim_outputs_config(FAR struct stm32_hrtim_s *priv);
static int hrtim_outputs_enable(FAR struct hrtim_dev_s *dev, uint16_t outputs,
bool state);
+static int hrtim_output_set_set(FAR struct hrtim_dev_s *dev, uint16_t output,
+ uint32_t set);
+static int hrtim_output_rst_set(FAR struct hrtim_dev_s *dev, uint16_t output,
+ uint32_t rst);
#endif
#ifdef HRTIM_HAVE_ADC
static int hrtim_adc_config(FAR struct stm32_hrtim_s *priv);
@@ -658,13 +663,14 @@ static int hrtim_tim_dma_cfg(FAR struct stm32_hrtim_s *priv, uint8_t timer,
uint16_t dma);
#endif
#ifdef CONFIG_STM32_HRTIM_DEADTIME
-static int hrtim_deadtime_update(FAR struct stm32_dev_s *dev, uint8_t dt,
- uint16_t value)
-static uint16_t hrtim_deadtime_get(FAR struct stm32_dev_s *dev, uint8_t dt);
+static int hrtim_deadtime_update(FAR struct hrtim_dev_s *dev, uint8_t timer,
+ uint8_t dt, uint16_t value);
+static uint16_t hrtim_deadtime_get(FAR struct hrtim_dev_s *dev, uint8_t dt);
+static int hrtim_tim_deadtime_cfg(FAR struct stm32_hrtim_s *priv, uint8_t timer);
static int hrtim_deadtime_config(FAR struct stm32_hrtim_s *priv);
#endif
#ifdef CONFIG_STM32_HRTIM_CHOPPER
-static int hrtim_chopper_enable(FAR struct stm32_dev_s *dev, uint8_t timer,
+static int hrtim_chopper_enable(FAR struct hrtim_dev_s *dev, uint8_t timer,
uint8_t chan, bool state);
static int hrtim_tim_chopper_cfg(FAR struct stm32_hrtim_s *priv, uint8_t timer);
static int hrtim_chopper_config(FAR struct stm32_hrtim_s *priv);
@@ -816,13 +822,14 @@ static struct stm32_hrtim_slave_priv_s g_tima_priv =
#ifdef CONFIG_STM32_HRTIM_TIMA_DT
.dt =
{
- .fsign_lock = HRTIM_TIMA_DT_RSLOCK,
+ .en = 1,
+ .fsign_lock = HRTIM_TIMA_DT_FSLOCK,
.rsign_lock = HRTIM_TIMA_DT_RSLOCK,
- .rising_lock = HRTIM_TIMA_DT_RVLOCK,
.falling_lock = HRTIM_TIMA_DT_FVLOCK,
+ .rising_lock = HRTIM_TIMA_DT_RVLOCK,
.fsign = HRTIM_TIMA_DT_FSIGN,
.rsign = HRTIM_TIMA_DT_RSIGN,
- .prescaler = HRTIM_TIMA_DT_PRESALER
+ .prescaler = HRTIM_TIMA_DT_PRESCALER
}
#endif
},
@@ -911,13 +918,14 @@ static struct stm32_hrtim_slave_priv_s g_timb_priv =
#ifdef CONFIG_STM32_HRTIM_TIMB_DT
.dt =
{
- .fsign_lock = HRTIM_TIMB_DT_RSLOCK,
+ .en = 1,
+ .fsign_lock = HRTIM_TIMB_DT_FSLOCK,
.rsign_lock = HRTIM_TIMB_DT_RSLOCK,
- .rising_lock = HRTIM_TIMB_DT_RVLOCK,
.falling_lock = HRTIM_TIMB_DT_FVLOCK,
+ .rising_lock = HRTIM_TIMB_DT_RVLOCK,
.fsign = HRTIM_TIMB_DT_FSIGN,
.rsign = HRTIM_TIMB_DT_RSIGN,
- .prescaler = HRTIM_TIMB_DT_PRESALER
+ .prescaler = HRTIM_TIMB_DT_PRESCALER
}
#endif
},
@@ -1006,13 +1014,14 @@ static struct stm32_hrtim_slave_priv_s g_timc_priv =
#ifdef CONFIG_STM32_HRTIM_TIMC_DT
.dt =
{
- .fsign_lock = HRTIM_TIMC_DT_RSLOCK,
+ .en = 1,
+ .fsign_lock = HRTIM_TIMC_DT_FSLOCK,
.rsign_lock = HRTIM_TIMC_DT_RSLOCK,
- .rising_lock = HRTIM_TIMC_DT_RVLOCK,
.falling_lock = HRTIM_TIMC_DT_FVLOCK,
+ .rising_lock = HRTIM_TIMC_DT_RVLOCK,
.fsign = HRTIM_TIMC_DT_FSIGN,
.rsign = HRTIM_TIMC_DT_RSIGN,
- .prescaler = HRTIM_TIMC_DT_PRESALER
+ .prescaler = HRTIM_TIMC_DT_PRESCALER
}
#endif
},
@@ -1101,13 +1110,14 @@ static struct stm32_hrtim_slave_priv_s g_timd_priv =
#ifdef CONFIG_STM32_HRTIM_TIMD_DT
.dt =
{
- .fsign_lock = HRTIM_TIMD_DT_RSLOCK,
+ .en = 1,
+ .fsign_lock = HRTIM_TIMD_DT_FSLOCK,
.rsign_lock = HRTIM_TIMD_DT_RSLOCK,
- .rising_lock = HRTIM_TIMD_DT_RVLOCK,
.falling_lock = HRTIM_TIMD_DT_FVLOCK,
+ .rising_lock = HRTIM_TIMD_DT_RVLOCK,
.fsign = HRTIM_TIMD_DT_FSIGN,
.rsign = HRTIM_TIMD_DT_RSIGN,
- .prescaler = HRTIM_TIMD_DT_PRESALER
+ .prescaler = HRTIM_TIMD_DT_PRESCALER
}
#endif
},
@@ -1196,13 +1206,14 @@ static struct stm32_hrtim_slave_priv_s g_time_priv =
#ifdef CONFIG_STM32_HRTIM_TIME_DT
.dt =
{
- .fsign_lock = HRTIM_TIME_DT_RSLOCK,
+ .en = 1,
+ .fsign_lock = HRTIM_TIME_DT_FSLOCK,
.rsign_lock = HRTIM_TIME_DT_RSLOCK,
- .rising_lock = HRTIM_TIME_DT_RVLOCK,
.falling_lock = HRTIM_TIME_DT_FVLOCK,
+ .rising_lock = HRTIM_TIME_DT_RVLOCK,
.fsign = HRTIM_TIME_DT_FSIGN,
.rsign = HRTIM_TIME_DT_RSIGN,
- .prescaler = HRTIM_TIME_DT_PRESALER
+ .prescaler = HRTIM_TIME_DT_PRESCALER
}
#endif
},
@@ -1482,6 +1493,8 @@ static const struct stm32_hrtim_ops_s g_hrtim1ops =
#endif
#ifdef CONFIG_STM32_HRTIM_PWM
.outputs_enable = hrtim_outputs_enable,
+ .output_rst_set = hrtim_output_rst_set,
+ .output_set_set = hrtim_output_set_set,
#endif
#ifdef CONFIG_STM32_HRTIM_BURST
.burst_enable = hrtim_burst_enable,
@@ -2151,6 +2164,10 @@ static int hrtim_tim_clock_config(FAR struct stm32_hrtim_s *priv,
}
}
+ /* Write prescaler configuration */
+
+ hrtim_tim_putreg(priv, timer, STM32_HRTIM_TIM_CR_OFFSET, regval);
+
errout:
return ret;
}
@@ -2637,9 +2654,8 @@ static int hrtim_tim_outputs_config(FAR struct stm32_hrtim_s *priv, uint8_t time
{
FAR struct stm32_hrtim_tim_s* tim;
FAR struct stm32_hrtim_slave_priv_s* slave;
-
- int ret = OK;
uint32_t regval = 0;
+ int ret = OK;
/* Master Timer has no outputs */
@@ -2724,6 +2740,24 @@ static int hrtim_tim_outputs_config(FAR struct stm32_hrtim_s *priv, uint8_t time
}
#endif
+#ifdef CONFIG_STM32_HRTIM_DEADTIME
+ if (slave->pwm.dt.en == 1)
+ {
+ regval = 0;
+
+ /* Set deadtime enable */
+
+ regval |= HRTIM_TIMOUT_DTEN;
+
+ /* TODO: deadtime upon burst mode Idle entry */
+
+ /* Write register */
+
+ hrtim_tim_modifyreg(priv, timer, STM32_HRTIM_TIM_OUTR_OFFSET, 0,
+ regval);
+ }
+#endif
+
errout:
return ret;
}
@@ -2841,6 +2875,243 @@ static int hrtim_outputs_enable(FAR struct hrtim_dev_s *dev,
return OK;
}
+
+/****************************************************************************
+ * Name: output_tim_index_get
+ ****************************************************************************/
+
+static uint8_t output_tim_index_get(uint16_t output)
+{
+ uint8_t timer = 0;
+
+ switch(output)
+ {
+#ifdef CONFIG_STM32_HRTIM_TIMA
+ case HRTIM_OUT_TIMA_CH1:
+ case HRTIM_OUT_TIMA_CH2:
+ {
+ timer = HRTIM_TIMER_TIMA;
+ break;
+ }
+#endif
+
+#ifdef CONFIG_STM32_HRTIM_TIMB
+ case HRTIM_OUT_TIMB_CH1:
+ case HRTIM_OUT_TIMB_CH2:
+ {
+ timer = HRTIM_TIMER_TIMB;
+ break;
+ }
+#endif
+
+#ifdef CONFIG_STM32_HRTIM_TIMC
+ case HRTIM_OUT_TIMC_CH1:
+ case HRTIM_OUT_TIMC_CH2:
+ {
+ timer = HRTIM_TIMER_TIMC;
+ break;
+ }
+#endif
+
+#ifdef CONFIG_STM32_HRTIM_TIMD
+ case HRTIM_OUT_TIMD_CH1:
+ case HRTIM_OUT_TIMD_CH2:
+ {
+ timer = HRTIM_TIMER_TIMD;
+ break;
+ }
+#endif
+
+#ifdef CONFIG_STM32_HRTIM_TIME
+ case HRTIM_OUT_TIME_CH1:
+ case HRTIM_OUT_TIME_CH2:
+ {
+ timer = HRTIM_TIMER_TIME;
+ break;
+ }
+#endif
+
+ default:
+ {
+ timer = 0;
+ break;
+ }
+ }
+
+ return timer;
+}
+
+/****************************************************************************
+ * Name: output_tim_ch_get
+ ****************************************************************************/
+
+static uint8_t output_tim_ch_get(uint16_t output)
+{
+ uint8_t ch = 0;
+
+ switch (output)
+ {
+#ifdef CONFIG_STM32_HRTIM_TIMA
+ case HRTIM_OUT_TIMA_CH1:
+#endif
+#ifdef CONFIG_STM32_HRTIM_TIMB
+ case HRTIM_OUT_TIMB_CH1:
+#endif
+#ifdef CONFIG_STM32_HRTIM_TIMC
+ case HRTIM_OUT_TIMC_CH1:
+#endif
+#ifdef CONFIG_STM32_HRTIM_TIMD
+ case HRTIM_OUT_TIMD_CH1:
+#endif
+#ifdef CONFIG_STM32_HRTIM_TIME
+ case HRTIM_OUT_TIME_CH1:
+#endif
+ {
+ ch = HRTIM_OUT_CH1;
+ break;
+ }
+
+#ifdef CONFIG_STM32_HRTIM_TIMA
+ case HRTIM_OUT_TIMA_CH2:
+#endif
+#ifdef CONFIG_STM32_HRTIM_TIMB
+ case HRTIM_OUT_TIMB_CH2:
+#endif
+#ifdef CONFIG_STM32_HRTIM_TIMC
+ case HRTIM_OUT_TIMC_CH2:
+#endif
+#ifdef CONFIG_STM32_HRTIM_TIMD
+ case HRTIM_OUT_TIMD_CH2:
+#endif
+#ifdef CONFIG_STM32_HRTIM_TIME
+ case HRTIM_OUT_TIME_CH2:
+#endif
+ {
+ ch = HRTIM_OUT_CH2;
+ break;
+ }
+
+ default:
+ {
+ ch = 0;
+ break;
+ }
+ }
+
+ return ch;
+}
+
+/****************************************************************************
+ * Name: hrtim_output_set_set
+ ****************************************************************************/
+
+static int hrtim_output_set_set(FAR struct hrtim_dev_s *dev, uint16_t output,
+ uint32_t set)
+{
+ FAR struct stm32_hrtim_s *priv = (FAR struct stm32_hrtim_s *)dev->hd_priv;
+ FAR struct stm32_hrtim_tim_s* tim;
+ FAR struct stm32_hrtim_slave_priv_s* slave;
+ uint8_t timer = 0;
+ int ret = OK;
+
+ /* Get timer index from output */
+
+ timer = output_tim_index_get(output);
+
+ /* Get Timer data strucutre */
+
+ tim = hrtim_tim_get(priv, timer);
+ if (tim == NULL)
+ {
+ ret = -EINVAL;
+ goto errout;
+ }
+
+ slave = (struct stm32_hrtim_slave_priv_s*)tim->priv;
+
+ /* Set new SET value */
+
+ switch (output_tim_ch_get(output))
+ {
+ case HRTIM_OUT_CH1:
+ {
+ slave->pwm.ch1.set = set;
+ hrtim_tim_putreg(priv, timer, STM32_HRTIM_TIM_SET1R_OFFSET, set);
+ break;
+ }
+
+ case HRTIM_OUT_CH2:
+ {
+ slave->pwm.ch2.set = set;
+ hrtim_tim_putreg(priv, timer, STM32_HRTIM_TIM_SET2R_OFFSET, set);
+ break;
+ }
+
+ default:
+ {
+ ret = -EINVAL;
+ goto errout;
+ }
+ }
+
+errout:
+ return ret;
+}
+
+/****************************************************************************
+ * Name: hrtim_output_rst_set
+ ****************************************************************************/
+static int hrtim_output_rst_set(FAR struct hrtim_dev_s *dev, uint16_t output,
+ uint32_t rst)
+{
+ FAR struct stm32_hrtim_s *priv = (FAR struct stm32_hrtim_s *)dev->hd_priv;
+ FAR struct stm32_hrtim_tim_s* tim;
+ FAR struct stm32_hrtim_slave_priv_s* slave;
+ uint8_t timer = 0;
+ int ret = OK;
+
+ /* Get timer index from output */
+
+ timer = output_tim_index_get(output);
+
+ /* Get Timer data strucutre */
+
+ tim = hrtim_tim_get(priv, timer);
+ if (tim == NULL)
+ {
+ ret = -EINVAL;
+ goto errout;
+ }
+
+ slave = (struct stm32_hrtim_slave_priv_s*)tim->priv;
+
+ /* Set new RST value */
+
+ switch (output_tim_ch_get(output))
+ {
+ case HRTIM_OUT_CH1:
+ {
+ slave->pwm.ch1.rst = rst;
+ hrtim_tim_putreg(priv, timer, STM32_HRTIM_TIM_RST1R_OFFSET, rst);
+ }
+
+ case HRTIM_OUT_CH2:
+ {
+ slave->pwm.ch2.rst = rst;
+ hrtim_tim_putreg(priv, timer, STM32_HRTIM_TIM_RST2R_OFFSET, rst);
+ }
+
+ default:
+ {
+ ret = -EINVAL;
+ goto errout;
+ }
+ }
+
+errout:
+ return ret;
+}
+
#endif
/****************************************************************************
@@ -3069,7 +3340,7 @@ static int hrtim_dma_cfg(FAR struct stm32_hrtim_s *priv)
* Name: hrtim_deadtime_update
****************************************************************************/
-static int hrtim_deadtime_update(FAR struct stm32_dev_s *dev, uint8_t timer,
+static int hrtim_deadtime_update(FAR struct hrtim_dev_s *dev, uint8_t timer,
uint8_t dt, uint16_t value)
{
FAR struct stm32_hrtim_s *priv = (FAR struct stm32_hrtim_s *)dev->hd_priv;
@@ -3078,17 +3349,18 @@ static int hrtim_deadtime_update(FAR struct stm32_dev_s *dev, uint8_t timer,
uint32_t shift = 0;
uint32_t mask = 0;
- /* Sanity check */
+ /* For safety reasons we saturate deadtime value if it exceeds
+ * the acceptable range.
+ */
if (value > 0x1FF)
{
- ret = -EINVAL;
- goto errout;
+ value = 0x1FF;
}
/* Get shift value */
- switch (index)
+ switch (dt)
{
case HRTIM_DT_EDGE_RISING:
{
@@ -3115,7 +3387,7 @@ static int hrtim_deadtime_update(FAR struct stm32_dev_s *dev, uint8_t timer,
/* Update register */
- hrtim_tim_modify(priv, timer, STM32_HRTIM_TIM_DTR_OFFSET, mask, regval);
+ hrtim_tim_modifyreg(priv, timer, STM32_HRTIM_TIM_DTR_OFFSET, mask, regval);
errout:
return ret;
@@ -3125,7 +3397,7 @@ errout:
* Name: hrtim_deadtime_get
****************************************************************************/
-static uint16_t hrtim_deadtime_get(FAR struct stm32_dev_s *dev, uint8_t dt)
+static uint16_t hrtim_deadtime_get(FAR struct hrtim_dev_s *dev, uint8_t dt)
{
#warning missing logic
}
@@ -3134,20 +3406,36 @@ static uint16_t hrtim_deadtime_get(FAR struct stm32_dev_s *dev, uint8_t dt)
* Name: hrtim_tim_deadtime_cfg
****************************************************************************/
-static int hrtim_tim_deadtime_cfg(FAR struct stm32_hrtim_s *priv, uint8_t index)
+static int hrtim_tim_deadtime_cfg(FAR struct stm32_hrtim_s *priv, uint8_t timer)
{
+ FAR struct stm32_hrtim_tim_s* tim;
FAR struct stm32_hrtim_slave_priv_s* slave;
uint32_t regval = 0;
int ret = OK;
+ /* Master Timer has no outputs */
+
if (timer == HRTIM_TIMER_MASTER)
{
ret = -EINVAL;
goto errout;
}
+ /* Get Timer data strucutre */
+
+ tim = hrtim_tim_get(priv, timer);
+ if (tim == NULL)
+ {
+ ret = -EINVAL;
+ goto errout;
+ }
+
slave = (struct stm32_hrtim_slave_priv_s*)tim->priv;
+ /* Configure deadtime prescaler */
+
+ regval |= slave->pwm.dt.prescaler << HRTIM_TIMDT_DTPRSC_SHIFT;
+
/* Configure rising deadtime */
regval |= slave->pwm.dt.rising << HRTIM_TIMDT_DTR_SHIFT;
@@ -3158,14 +3446,14 @@ static int hrtim_tim_deadtime_cfg(FAR struct stm32_hrtim_s *priv, uint8_t index)
/* Configure falling deadtime sign */
- if (slave->pwm.dt.fsign == HRTIM_DT_SIGN_POSITIVE)
+ if (slave->pwm.dt.fsign == HRTIM_DT_SIGN_NEGATIVE)
{
regval |= HRTIM_TIMDT_SDTF;
}
/* Configure risign deadtime sign */
- if (slave->pwm.dt.rsign == HRTIM_DT_SIGN_POSITIVE)
+ if (slave->pwm.dt.rsign == HRTIM_DT_SIGN_NEGATIVE)
{
regval |= HRTIM_TIMDT_SDTR;
}
@@ -3198,6 +3486,12 @@ static int hrtim_tim_deadtime_cfg(FAR struct stm32_hrtim_s *priv, uint8_t index)
regval |= HRTIM_TIMDT_DTFLK;
}
+ /* TODO: configure default deadtime values */
+
+ /* Write register */
+
+ hrtim_tim_putreg(priv, timer, STM32_HRTIM_TIM_DTR_OFFSET, regval);
+
errout:
return ret;
}
@@ -3210,31 +3504,31 @@ static int hrtim_deadtime_config(FAR struct stm32_hrtim_s *priv)
{
/* Configure Timer A deadtime */
-#ifdef CONFIG_STM32_HRTIM_TIMA
+#ifdef CONFIG_STM32_HRTIM_TIMA_DT
hrtim_tim_deadtime_cfg(priv, HRTIM_TIMER_TIMA);
#endif
/* Configure Timer B deadtime */
-#ifdef CONFIG_STM32_HRTIM_TIMB
+#ifdef CONFIG_STM32_HRTIM_TIMB_DT
hrtim_tim_deadtime_cfg(priv, HRTIM_TIMER_TIMB);
#endif
/* Configure Timer C deadtime */
-#ifdef CONFIG_STM32_HRTIM_TIMC
+#ifdef CONFIG_STM32_HRTIM_TIMC_DT
hrtim_tim_deadtime_cfg(priv, HRTIM_TIMER_TIMC);
#endif
/* Configure Timer D deadtime */
-#ifdef CONFIG_STM32_HRTIM_TIMD
+#ifdef CONFIG_STM32_HRTIM_TIMD_DT
hrtim_tim_deadtime_cfg(priv, HRTIM_TIMER_TIMD);
#endif
/* Configure Timer E deadtime */
-#ifdef CONFIG_STM32_HRTIM_TIME
+#ifdef CONFIG_STM32_HRTIM_TIME_DT
hrtim_tim_deadtime_cfg(priv, HRTIM_TIMER_TIME);
#endif
@@ -3260,7 +3554,7 @@ static int hrtim_deadtime_config(FAR struct stm32_hrtim_s *priv)
*
****************************************************************************/
-static int hrtim_chopper_enable(FAR struct stm32_dev_s *dev, uint8_t timer,
+static int hrtim_chopper_enable(FAR struct hrtim_dev_s *dev, uint8_t timer,
uint8_t chan, bool state)
{
FAR struct stm32_hrtim_s *priv = (FAR struct stm32_hrtim_s *)dev->hd_priv;
@@ -4595,6 +4889,17 @@ static int stm32_hrtimconfig(FAR struct stm32_hrtim_s *priv)
}
#endif
+ /* Configure HRTIM outputs deadtime */
+
+#if defined(CONFIG_STM32_HRTIM_DEADTIME)
+ ret = hrtim_deadtime_config(priv);
+ if (ret != OK)
+ {
+ tmrerr("ERROR: HRTIM deadtime configuration failed!\n");
+ goto errout;
+ }
+#endif
+
/* Configure HRTIM outputs GPIOs */
#if defined(CONFIG_STM32_HRTIM_PWM)
diff --git a/arch/arm/src/stm32/stm32_hrtim.h b/arch/arm/src/stm32/stm32_hrtim.h
index 1085951fb90..40ffe37b8dc 100644
--- a/arch/arm/src/stm32/stm32_hrtim.h
+++ b/arch/arm/src/stm32/stm32_hrtim.h
@@ -208,10 +208,12 @@
(hrtim)->hd_ops->cmp_update(hrtim, tim, index, cmp)
#define HRTIM_PER_SET(hrtim, tim, per) \
(hrtim)->hd_ops->per_update(hrtim, tim, per)
-#define HRTIM_OUTPUTS_ENABLE(hrtim, tim, state) \
- (hrtim)->hd_ops->outputs_enable(hrtim, tim, state)
-#define HRTIM_OUTPUTS_ENABLE(hrtim, tim, state) \
- (hrtim)->hd_ops->outputs_enable(hrtim, tim, state)
+#define HRTIM_OUTPUTS_ENABLE(hrtim, outputs, state) \
+ (hrtim)->hd_ops->outputs_enable(hrtim, outputs, state)
+#define HRTIM_OUTPUT_SET_SET(hrtim, output, set) \
+ (hrtim)->hd_ops->output_set_set(hrtim, output, set)
+#define HRTIM_OUTPUT_RST_SET(hrtim, output, rst) \
+ (hrtim)->hd_ops->output_rst_set(hrtim, output, rst)
#define HRTIM_BURST_CMP_SET(hrtim, cmp) \
(hrtim)->hd_ops->burst_cmp_set(hrtim, cmp)
#define HRTIM_BURST_PER_SET(hrtim, per) \
@@ -220,6 +222,8 @@
(hrtim)->hd_ops->burst_pre_set(hrtim, pre)
#define HRTIM_BURST_ENABLE(hrtim, state) \
(hrtim)->hd_ops->burst_enable(hrtim, state)
+#define HRTIM_DEADTIME_UPDATE(hrtim, tim, dt, val) \
+ (hrtim)->hd_ops->deadtime_update(hrtim, tim, dt, val)
/************************************************************************************
* Public Types
@@ -229,23 +233,23 @@
enum stm32_hrtim_tim_e
{
- HRTIM_TIMER_MASTER = 0,
+ HRTIM_TIMER_MASTER = (1<<0),
#ifdef CONFIG_STM32_HRTIM_TIMA
- HRTIM_TIMER_TIMA = 1,
+ HRTIM_TIMER_TIMA = (1<<1),
#endif
#ifdef CONFIG_STM32_HRTIM_TIMB
- HRTIM_TIMER_TIMB = 2,
+ HRTIM_TIMER_TIMB = (1<<2),
#endif
#ifdef CONFIG_STM32_HRTIM_TIMC
- HRTIM_TIMER_TIMC = 3,
+ HRTIM_TIMER_TIMC = (1<<3),
#endif
#ifdef CONFIG_STM32_HRTIM_TIMD
- HRTIM_TIMER_TIMD = 4,
+ HRTIM_TIMER_TIMD = (1<<4),
#endif
#ifdef CONFIG_STM32_HRTIM_TIME
- HRTIM_TIMER_TIME = 5,
+ HRTIM_TIMER_TIME = (1<<5),
#endif
- HRTIM_TIMER_COMMON = 6
+ HRTIM_TIMER_COMMON = (1<<6)
};
/* Source which can force the Tx1/Tx2 output to its inactive state */
@@ -571,7 +575,7 @@ enum stm32_outputs_e
enum stm32_hrtim_deadtime_sign_e
{
HRTIM_DT_SIGN_POSITIVE = 0,
- HRTIM_DT_DIGN_NEGATIVE = 1
+ HRTIM_DT_SIGN_NEGATIVE = 1
};
/* HRTIM Deadtime types */
@@ -973,6 +977,10 @@ struct stm32_hrtim_ops_s
#ifdef CONFIG_STM32_HRTIM_PWM
int (*outputs_enable)(FAR struct hrtim_dev_s *dev, uint16_t outputs,
bool state);
+ int (*output_set_set)(FAR struct hrtim_dev_s *dev, uint16_t output,
+ uint32_t set);
+ int (*output_rst_set)(FAR struct hrtim_dev_s *dev, uint16_t output,
+ uint32_t rst);
#endif
#ifdef CONFIG_STM32_HRTIM_BURST
int (*burst_enable)(FAR struct hrtim_dev_s *dev, bool state);
@@ -988,8 +996,10 @@ struct stm32_hrtim_ops_s
uint8_t chan, bool state);
#endif
#ifdef CONFIG_STM32_HRTIM_DEADTIME
- int (*deadtime_update)(FAR struct hrtim_dev_s *dev, uint8_t dt, uint16_t value);
- uint16_t (*deadtime_get)(FAR struct hrtim_dev_s *dev, uint8_t dt);
+ int (*deadtime_update)(FAR struct hrtim_dev_s *dev, uint8_t timer,
+ uint8_t dt, uint16_t value);
+ uint16_t (*deadtime_get)(FAR struct hrtim_dev_s *dev, uint8_t timer,
+ uint8_t dt);
#endif
#ifdef CONFIG_STM32_HRTIM_CAPTURE
uint16_t (*capture_get)(FAR struct hrtim_dev_s *dev, uint8_t timer,
diff --git a/arch/arm/src/stm32f7/Kconfig b/arch/arm/src/stm32f7/Kconfig
index 9e80a64934b..4f07188d097 100644
--- a/arch/arm/src/stm32f7/Kconfig
+++ b/arch/arm/src/stm32f7/Kconfig
@@ -1430,6 +1430,7 @@ config STM32F7_SDMMC1
select ARCH_HAVE_SDIO
select ARCH_HAVE_SDIOWAIT_WRCOMPLETE
select SDIO_PREFLIGHT
+ select SDIO_BLOCKSETUP
config STM32F7_SDMMC2
bool "SDMMC2"
@@ -1439,6 +1440,7 @@ config STM32F7_SDMMC2
select ARCH_HAVE_SDIO
select ARCH_HAVE_SDIOWAIT_WRCOMPLETE
select SDIO_PREFLIGHT
+ select SDIO_BLOCKSETUP
config STM32F7_SPDIFRX
bool "SPDIFRX"
diff --git a/arch/arm/src/stm32f7/stm32_sdmmc.c b/arch/arm/src/stm32f7/stm32_sdmmc.c
index e6168ad6631..e5ac6632df6 100644
--- a/arch/arm/src/stm32f7/stm32_sdmmc.c
+++ b/arch/arm/src/stm32f7/stm32_sdmmc.c
@@ -1,7 +1,7 @@
/****************************************************************************
* arch/arm/src/stm32f7/stm32_sdmmc.c
*
- * Copyright (C) 2009, 2011-2017 Gregory Nutt. All rights reserved.
+ * Copyright (C) 2009, 2011-2018 Gregory Nutt. All rights reserved.
* Authors: Gregory Nutt
* David Sidrane
*
@@ -388,6 +388,10 @@ struct stm32_dev_s
bool dmamode; /* true: DMA mode transfer */
DMA_HANDLE dma; /* Handle for DMA channel */
#endif
+
+ /* Misc */
+
+ uint32_t blocksize; /* Current block size */
};
/* Register logging support */
@@ -421,8 +425,8 @@ struct stm32_sampleregs_s
/* Low-level helpers ********************************************************/
-static inline void sdmmc_putreg32(struct stm32_dev_s *priv, uint32_t value,\
- int offset);
+static inline void sdmmc_putreg32(struct stm32_dev_s *priv, uint32_t value,
+ int offset);
static inline uint32_t sdmmc_getreg32(struct stm32_dev_s *priv, int offset);
static void stm32_takesem(struct stm32_dev_s *priv);
#define stm32_givesem(priv) (nxsem_post(&priv->waitsem))
@@ -438,7 +442,7 @@ static inline uint32_t stm32_getpwrctrl(struct stm32_dev_s *priv);
#ifdef CONFIG_STM32F7_SDMMC_XFRDEBUG
static void stm32_sampleinit(void);
static void stm32_sdiosample(struct stm32_dev_s *priv,
- struct stm32_sdioregs_s *regs);
+ struct stm32_sdioregs_s *regs);
static void stm32_sample(struct stm32_dev_s *priv, int index);
static void stm32_sdiodump(struct stm32_sdioregs_s *regs, const char *msg);
static void stm32_dumpsample(struct stm32_dev_s *priv,
@@ -458,13 +462,15 @@ static void stm32_dmacallback(DMA_HANDLE handle, uint8_t status, void *arg);
static uint8_t stm32_log2(uint16_t value);
static void stm32_dataconfig(struct stm32_dev_s *priv, uint32_t timeout,
- uint32_t dlen, uint32_t dctrl);
+ uint32_t dlen, uint32_t dctrl);
static void stm32_datadisable(struct stm32_dev_s *priv);
static void stm32_sendfifo(struct stm32_dev_s *priv);
static void stm32_recvfifo(struct stm32_dev_s *priv);
static void stm32_eventtimeout(int argc, uint32_t arg);
-static void stm32_endwait(struct stm32_dev_s *priv, sdio_eventset_t wkupevent);
-static void stm32_endtransfer(struct stm32_dev_s *priv, sdio_eventset_t wkupevent);
+static void stm32_endwait(struct stm32_dev_s *priv,
+ sdio_eventset_t wkupevent);
+static void stm32_endtransfer(struct stm32_dev_s *priv,
+ sdio_eventset_t wkupevent);
/* Interrupt Handling *******************************************************/
@@ -495,6 +501,8 @@ static int stm32_attach(FAR struct sdio_dev_s *dev);
static int stm32_sendcmd(FAR struct sdio_dev_s *dev, uint32_t cmd,
uint32_t arg);
+static void stm32_blocksetup(FAR struct sdio_dev_s *dev,
+ unsigned int blocksize, unsigned int nblocks);
static int stm32_recvsetup(FAR struct sdio_dev_s *dev, FAR uint8_t *buffer,
size_t nbytes);
static int stm32_sendsetup(FAR struct sdio_dev_s *dev,
@@ -543,6 +551,7 @@ static void stm32_default(struct stm32_dev_s *priv);
/****************************************************************************
* Private Data
****************************************************************************/
+
#ifdef CONFIG_STM32F7_SDMMC1
struct stm32_dev_s g_sdmmcdev1 =
{
@@ -558,9 +567,7 @@ struct stm32_dev_s g_sdmmcdev1 =
.clock = stm32_clock,
.attach = stm32_attach,
.sendcmd = stm32_sendcmd,
-#ifdef CONFIG_SDIO_BLOCKSETUP
- .blocksetup = stm32_blocksetup, /* Not implemented yet */
-#endif
+ .blocksetup = stm32_blocksetup,
.recvsetup = stm32_recvsetup,
.sendsetup = stm32_sendsetup,
.cancel = stm32_cancel,
@@ -620,9 +627,7 @@ struct stm32_dev_s g_sdmmcdev2 =
.clock = stm32_clock,
.attach = stm32_attach,
.sendcmd = stm32_sendcmd,
-#ifdef CONFIG_SDIO_BLOCKSETUP
- .blocksetup = stm32_blocksetup, /* Not implemented yet */
-#endif
+ .blocksetup = stm32_blocksetup,
.recvsetup = stm32_recvsetup,
.sendsetup = stm32_sendsetup,
.cancel = stm32_cancel,
@@ -1433,6 +1438,19 @@ static void stm32_endwait(struct stm32_dev_s *priv, sdio_eventset_t wkupevent)
static void stm32_endtransfer(struct stm32_dev_s *priv,
sdio_eventset_t wkupevent)
{
+ /* Disable the DTEN bit (it should not be left set after previous read when
+ * the next write initialization starts).
+ */
+
+#if 1
+ sdmmc_putreg32(priv,
+ sdmmc_getreg32(priv, STM32_SDMMC_DCTRL_OFFSET) &
+ ~STM32_SDMMC_DCTRL_DTEN,
+ STM32_SDMMC_DCTRL_OFFSET);
+#else
+ stm32_datadisable(priv);
+#endif
+
/* Disable all transfer related interrupts */
stm32_configxfrints(priv, 0);
@@ -2057,6 +2075,30 @@ static int stm32_sendcmd(FAR struct sdio_dev_s *dev, uint32_t cmd, uint32_t arg)
return OK;
}
+/****************************************************************************
+ * Name: stm32_blocksetup
+ *
+ * Description:
+ * Configure block size and the number of blocks for next transfer.
+ *
+ * Input Parameters:
+ * dev - An instance of the SDIO device interface.
+ * blocksize - The selected block size.
+ * nblocks - The number of blocks to transfer.
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+static void stm32_blocksetup(FAR struct sdio_dev_s *dev, unsigned int blocksize,
+ unsigned int nblocks)
+{
+ struct stm32_dev_s *priv = (struct stm32_dev_s *)dev;
+
+ priv->blocksize = blocksize;
+}
+
/****************************************************************************
* Name: stm32_recvsetup
*
@@ -2103,7 +2145,7 @@ static int stm32_recvsetup(FAR struct sdio_dev_s *dev, FAR uint8_t *buffer,
/* Then set up the SDIO data path */
- dblocksize = stm32_log2(nbytes) << STM32_SDMMC_DCTRL_DBLOCKSIZE_SHIFT;
+ dblocksize = stm32_log2(priv->blocksize) << STM32_SDMMC_DCTRL_DBLOCKSIZE_SHIFT;
stm32_dataconfig(priv, SDMMC_DTIMER_DATATIMEOUT, nbytes, dblocksize |
STM32_SDMMC_DCTRL_DTDIR);
@@ -2158,7 +2200,7 @@ static int stm32_sendsetup(FAR struct sdio_dev_s *dev, FAR const
/* Then set up the SDIO data path */
- dblocksize = stm32_log2(nbytes) << STM32_SDMMC_DCTRL_DBLOCKSIZE_SHIFT;
+ dblocksize = stm32_log2(priv->blocksize) << STM32_SDMMC_DCTRL_DBLOCKSIZE_SHIFT;
stm32_dataconfig(priv, SDMMC_DTIMER_DATATIMEOUT, nbytes, dblocksize);
/* Enable TX interrupts */
@@ -2882,7 +2924,7 @@ static int stm32_dmarecvsetup(FAR struct sdio_dev_s *dev, FAR uint8_t *buffer,
/* Then set up the SDIO data path */
- dblocksize = stm32_log2(buflen) << STM32_SDMMC_DCTRL_DBLOCKSIZE_SHIFT;
+ dblocksize = stm32_log2(priv->blocksize) << STM32_SDMMC_DCTRL_DBLOCKSIZE_SHIFT;
stm32_dataconfig(priv, SDMMC_DTIMER_DATATIMEOUT, buflen, dblocksize |
STM32_SDMMC_DCTRL_DTDIR);
@@ -2975,7 +3017,7 @@ static int stm32_dmasendsetup(FAR struct sdio_dev_s *dev,
/* Then set up the SDIO data path */
- dblocksize = stm32_log2(buflen) << STM32_SDMMC_DCTRL_DBLOCKSIZE_SHIFT;
+ dblocksize = stm32_log2(priv->blocksize) << STM32_SDMMC_DCTRL_DBLOCKSIZE_SHIFT;
stm32_dataconfig(priv, SDMMC_DTIMER_DATATIMEOUT, buflen, dblocksize);
/* Configure the TX DMA */
diff --git a/configs/lpcxpresso-lpc54628/README.txt b/configs/lpcxpresso-lpc54628/README.txt
index 31a65ff18e3..0f31315c946 100644
--- a/configs/lpcxpresso-lpc54628/README.txt
+++ b/configs/lpcxpresso-lpc54628/README.txt
@@ -24,6 +24,12 @@ README
device functionality
- 10/100Mbps Ethernet (RJ45 connector)
+CONTENTS
+========
+
+ - STATUS
+ - Configurations
+
STATUS
======
@@ -86,20 +92,13 @@ STATUS
of this writing. Also added the netnsh configuration will, eventually,
be used to test the Ethernet driver.
2018-01-01: There Ethernet driver appears to be fully functional although
- more testing is certainly needed. I believe that there is a memory
- corruption issue in the current configuration that cause problems
- occasionally. For example, after a longer Telnet session, I sometimes
- see the following DEBUGASSERT after exiting the session from the host:
+ more testing is certainly needed.
+ 2018-01-14: The basic SPI driver is code complete but still untested. It
+ is "basic" in the sense that it supports only polled mode (no DMA).
- up_assert: Assertion failed at file:mm_heap/mm_free.c line: 129
-
- which is a clear indication heap corruption. Increasing the size of some
- stacks might correct this problem, but I have not yet experimented with
- that. I have not seen the problem in any other context.
-
- There is still no support for the Accelerometer, SPIFI, or USB. There is a
- complete but not-yet-functional SD card. There is a partial SPI driver,
- but no on-board SPI devices to test it.
+ There is still no support for the Accelerometer, SPIFI, or USB. There are
+ complete but not-yet-functional SD card and SPI drivers. There are no
+ on-board devices to support SPI testing.
Configurations
==============
diff --git a/configs/lpcxpresso-lpc54628/fb/defconfig b/configs/lpcxpresso-lpc54628/fb/defconfig
index 2234418cfcc..2dc326a0794 100644
--- a/configs/lpcxpresso-lpc54628/fb/defconfig
+++ b/configs/lpcxpresso-lpc54628/fb/defconfig
@@ -64,7 +64,7 @@ CONFIG_PREALLOC_MQ_MSGS=4
CONFIG_PREALLOC_TIMERS=4
CONFIG_PREALLOC_WDOGS=4
CONFIG_RAM_SIZE=163840
-CONFIG_RAM_START=0x10000000
+CONFIG_RAM_START=0x20000000
CONFIG_RAW_BINARY=y
CONFIG_RR_INTERVAL=200
CONFIG_SCHED_HPWORK=y
diff --git a/configs/lpcxpresso-lpc54628/include/board.h b/configs/lpcxpresso-lpc54628/include/board.h
index 2ca923462a6..802d35575c0 100644
--- a/configs/lpcxpresso-lpc54628/include/board.h
+++ b/configs/lpcxpresso-lpc54628/include/board.h
@@ -306,7 +306,7 @@
/* Pin Disambiguation *******************************************************/
/* Flexcomm0/USART0
*
- * USART0 connects to the serial bridge on LPC4322JET100 and is typlical used
+ * USART0 connects to the serial bridge on LPC4322JET100 and is typically used
* for the serial console.
*
* BRIDGE_UART_RXD -> P0_29-ISP_FC0_RXD -> P0.29 GPIO_FC0_RXD_SDA_MOSI_2
@@ -316,6 +316,18 @@
#define GPIO_USART0_RXD (GPIO_FC0_RXD_SDA_MOSI_2 | GPIO_FILTER_OFF)
#define GPIO_USART0_TXD (GPIO_FC0_TXD_SCL_MISO_2 | GPIO_FILTER_OFF)
+/* An alternative for the serial console is a Arduino Uno compatible serial
+ * shield:
+ *
+ * Arduino Uno J13 Board Signal
+ * ----------- ------ ----------------
+ * D0 RX Pin 15 P3_26-FC4_RXD
+ * D1 TX Pin 13 P3_27-FC4_TXD
+ */
+
+#define GPIO_USART4_RXD (GPIO_FC4_RXD_SDA_MOSI_2 | GPIO_FILTER_OFF)
+#define GPIO_USART4_TXD (GPIO_FC4_TXD_SCL_MISO_2 | GPIO_FILTER_OFF)
+
/* Flexcomm2/I2C
*
* For I2C:
@@ -329,8 +341,14 @@
* Type I pins need for high speed I2C need:
* GPIO_FILTER_OFF + GPIO_I2C_FILTER_OFF + GPIO_I2CDRIVE_HIGH
*
- * The touchscreen controller is on I2C2: SCL P3.24, SDA P3.23. These are
- * both Type D/I pins.
+ * There are several on-board devices using I2C2:
+ *
+ * Codec I2C address: 0x1a
+ * Accel I2C address: 0x1d
+ * Touch panel I2C address: 0x38
+ *
+ * In addition, these same I2C2 pins are brought out through D14 and D15 of
+ * the Arduino Uno connector.
*/
#if defined(CONFIG_LPC54_I2C_FAST)
@@ -351,6 +369,35 @@
GPIO_FILTER_OFF | _I2CFILTER | \
_I2CDRIVE)
+/* Flexcomm2/SPI
+ *
+ * There are no SPI devices on board the LPCXpresso-LPC54628. SPI is
+ * available on the Arduino Uno compatible connector, however:
+ *
+ * Arduino Uno J9 Board Signal Pin Type
+ * ----------- ------ ---------------- ---------
+ * D10 SSEL Pin 15 P3_20-FC9_SCK Type D
+ * D11 MOSI Pin 13 P3_21-FC9_MOSI Type A
+ * D12 MISO Pin 11 P3_22-FC9_MISO Type A
+ * D13 SCK Pin 9 P3_30-FC9_SSELn0 Type D
+ *
+ * For SPI:
+ * Type A & D pins need:
+ * GPIO_PUSHPULL (on outputs) + GPIO_SLEW_STANDARD (Type D) +
+ * GPIO_FILTER_OFF
+ * GPIO_SLEW_FAST is optional for high data rates (Type D).
+ * Type I need:
+ * GPIO_I2C_FILTER_OFF + GPIO_I2CDRIVE_LOW + GPIO_FILTER_OFF +
+ * GPIO_I2CSLEW_GPIO
+ */
+
+#define GPIO_FC9_RXD_SDA_MOSI (GPIO_FC9_RXD_SDA_MOSI_1 | \
+ GPIO_PUSHPULL | GPIO_FILTER_OFF)
+#define GPIO_FC9_TXD_SCL_MISO (GPIO_FC9_TXD_SCL_MISO_1 | \
+ GPIO_FILTER_OFF)
+#define GPIO_FC9_SCK (GPIO_FC9_SCK_1 | GPIO_PUSHPULL | \
+ GPIO_SLEW_STANDARD | GPIO_FILTER_OFF)
+
/* SD/MMC
*
* P2_10-SD_CDn
@@ -412,7 +459,6 @@
* feature.
*/
-
#define GPIO_ENET_MDIO GPIO_ENET_MDIO_2 /* P4.16 */
#define GPIO_ENET_MDC GPIO_ENET_MDC_2 /* P4.15 */
diff --git a/configs/lpcxpresso-lpc54628/netnsh/defconfig b/configs/lpcxpresso-lpc54628/netnsh/defconfig
index 89836e60109..b84ff13d81e 100644
--- a/configs/lpcxpresso-lpc54628/netnsh/defconfig
+++ b/configs/lpcxpresso-lpc54628/netnsh/defconfig
@@ -55,7 +55,7 @@ CONFIG_PREALLOC_MQ_MSGS=4
CONFIG_PREALLOC_TIMERS=4
CONFIG_PREALLOC_WDOGS=4
CONFIG_RAM_SIZE=163840
-CONFIG_RAM_START=0x10000000
+CONFIG_RAM_START=0x20000000
CONFIG_RAW_BINARY=y
CONFIG_RR_INTERVAL=200
CONFIG_SCHED_HPWORK=y
diff --git a/configs/lpcxpresso-lpc54628/nsh/defconfig b/configs/lpcxpresso-lpc54628/nsh/defconfig
index 70d2e780688..bdcaa769d36 100644
--- a/configs/lpcxpresso-lpc54628/nsh/defconfig
+++ b/configs/lpcxpresso-lpc54628/nsh/defconfig
@@ -42,7 +42,7 @@ CONFIG_PREALLOC_MQ_MSGS=4
CONFIG_PREALLOC_TIMERS=4
CONFIG_PREALLOC_WDOGS=4
CONFIG_RAM_SIZE=163840
-CONFIG_RAM_START=0x10000000
+CONFIG_RAM_START=0x20000000
CONFIG_RAW_BINARY=y
CONFIG_RR_INTERVAL=200
CONFIG_RTC_ALARM=y
diff --git a/configs/lpcxpresso-lpc54628/nxwm/defconfig b/configs/lpcxpresso-lpc54628/nxwm/defconfig
index 4c2f839ee1a..5bc987dbb5e 100644
--- a/configs/lpcxpresso-lpc54628/nxwm/defconfig
+++ b/configs/lpcxpresso-lpc54628/nxwm/defconfig
@@ -87,7 +87,7 @@ CONFIG_NXWM=y
CONFIG_PREALLOC_TIMERS=4
CONFIG_PREALLOC_WDOGS=8
CONFIG_RAM_SIZE=163840
-CONFIG_RAM_START=0x10000000
+CONFIG_RAM_START=0x20000000
CONFIG_RAW_BINARY=y
CONFIG_RR_INTERVAL=200
CONFIG_SCHED_HPWORK=y
diff --git a/configs/lpcxpresso-lpc54628/scripts/flash.ld b/configs/lpcxpresso-lpc54628/scripts/flash.ld
index fc09e2fffc5..42a0396af85 100644
--- a/configs/lpcxpresso-lpc54628/scripts/flash.ld
+++ b/configs/lpcxpresso-lpc54628/scripts/flash.ld
@@ -33,7 +33,7 @@
*
****************************************************************************/
-/* The LPC54628 on the LPCXPressio has 512Kb of FLASH at address 0x0000:0000.
+/* The LPC54628 on the LPCXPresso has 512Kb of FLASH at address 0x0000:0000.
* The Main SRAM is comprised of up to a total 160 KB of contiguous, on-chip
* static RAM memory beginning at address 0x2000:0000 (this is in addition
* to SRAMX aso the total device SRAM can be up to 200 KB).
diff --git a/configs/nucleo-f072rb/src/stm32_userleds.c b/configs/nucleo-f072rb/src/stm32_userleds.c
index 0b967fc662d..8febc96b467 100644
--- a/configs/nucleo-f072rb/src/stm32_userleds.c
+++ b/configs/nucleo-f072rb/src/stm32_userleds.c
@@ -181,9 +181,9 @@ void board_userled_initialize(void)
void board_userled(int led, bool ledon)
{
- if (led == 1)
+ if (led == BOARD_LD2)
{
- stm32f0_gpiowrite(GPIO_LD2, ldeon);
+ stm32f0_gpiowrite(GPIO_LD2, ledon);
}
}
@@ -193,10 +193,7 @@ void board_userled(int led, bool ledon)
void board_userled_all(uint8_t ledset)
{
- if (led == 1)
- {
- stm32f0_gpiowrite(GPIO_LD2, (ledset & BOARD_LD2_BIT) != 0);
- }
+ stm32f0_gpiowrite(GPIO_LD2, (ledset & BOARD_LD2_BIT) != 0);
}
/****************************************************************************
diff --git a/configs/nucleo-f091rc/src/stm32_userleds.c b/configs/nucleo-f091rc/src/stm32_userleds.c
index b13c1882b73..f62e84a30e4 100644
--- a/configs/nucleo-f091rc/src/stm32_userleds.c
+++ b/configs/nucleo-f091rc/src/stm32_userleds.c
@@ -181,9 +181,9 @@ void board_userled_initialize(void)
void board_userled(int led, bool ledon)
{
- if (led == 1)
+ if (led == BOARD_LD2)
{
- stm32f0_gpiowrite(GPIO_LD2, ldeon);
+ stm32f0_gpiowrite(GPIO_LD2, ledon);
}
}
@@ -193,10 +193,7 @@ void board_userled(int led, bool ledon)
void board_userled_all(uint8_t ledset)
{
- if (led == 1)
- {
- stm32f0_gpiowrite(GPIO_LD2, (ledset & BOARD_LD2_BIT) != 0);
- }
+ stm32f0_gpiowrite(GPIO_LD2, (ledset & BOARD_LD2_BIT) != 0);
}
/****************************************************************************
diff --git a/configs/nucleo-f410rb/src/stm32_userleds.c b/configs/nucleo-f410rb/src/stm32_userleds.c
index bdd1be2b181..fb283a50cc7 100644
--- a/configs/nucleo-f410rb/src/stm32_userleds.c
+++ b/configs/nucleo-f410rb/src/stm32_userleds.c
@@ -181,9 +181,9 @@ void board_userled_initialize(void)
void board_userled(int led, bool ledon)
{
- if (led == 1)
+ if (led == BOARD_LD2)
{
- stm32_gpiowrite(GPIO_LD2, ldeon);
+ stm32_gpiowrite(GPIO_LD2, ledon);
}
}
@@ -193,10 +193,7 @@ void board_userled(int led, bool ledon)
void board_userled_all(uint8_t ledset)
{
- if (led == 1)
- {
- stm32_gpiowrite(GPIO_LD2, (ledset & BOARD_LD2_BIT) != 0);
- }
+ stm32_gpiowrite(GPIO_LD2, (ledset & BOARD_LD2_BIT) != 0);
}
/****************************************************************************
diff --git a/configs/nucleo-l432kc/src/stm32_userleds.c b/configs/nucleo-l432kc/src/stm32_userleds.c
index 0ff3ce66c86..8dec7afee3c 100644
--- a/configs/nucleo-l432kc/src/stm32_userleds.c
+++ b/configs/nucleo-l432kc/src/stm32_userleds.c
@@ -181,7 +181,7 @@ void board_userled_initialize(void)
void board_userled(int led, bool ledon)
{
- if (led == 1)
+ if (led == BOARD_LD2)
{
stm32l4_gpiowrite(GPIO_LD2, ledon);
}
@@ -193,10 +193,7 @@ void board_userled(int led, bool ledon)
void board_userled_all(uint8_t ledset)
{
- if (led == 1)
- {
- stm32l4_gpiowrite(GPIO_LD2, (ledset & BOARD_LD2_BIT) != 0);
- }
+ stm32l4_gpiowrite(GPIO_LD2, (ledset & BOARD_LD2_BIT) != 0);
}
/****************************************************************************
diff --git a/configs/nucleo-l452re/src/stm32_userleds.c b/configs/nucleo-l452re/src/stm32_userleds.c
index 77ba277c342..4ed1b8d807e 100644
--- a/configs/nucleo-l452re/src/stm32_userleds.c
+++ b/configs/nucleo-l452re/src/stm32_userleds.c
@@ -181,9 +181,9 @@ void board_userled_initialize(void)
void board_userled(int led, bool ledon)
{
- if (led == 1)
+ if (led == BOARD_LD2)
{
- stm32l4_gpiowrite(GPIO_LD2, ldeon);
+ stm32l4_gpiowrite(GPIO_LD2, ledon);
}
}
@@ -193,10 +193,7 @@ void board_userled(int led, bool ledon)
void board_userled_all(uint8_t ledset)
{
- if (led == 1)
- {
- stm32l4_gpiowrite(GPIO_LD2, (ledset & BOARD_LD2_BIT) != 0);
- }
+ stm32l4_gpiowrite(GPIO_LD2, (ledset & BOARD_LD2_BIT) != 0);
}
/****************************************************************************
diff --git a/configs/nucleo-l476rg/src/stm32_userleds.c b/configs/nucleo-l476rg/src/stm32_userleds.c
index 53d9193230a..9464a6ad341 100644
--- a/configs/nucleo-l476rg/src/stm32_userleds.c
+++ b/configs/nucleo-l476rg/src/stm32_userleds.c
@@ -172,7 +172,7 @@ void board_userled_initialize(void)
{
/* Configure LD2 GPIO for output */
- stm32_configgpio(GPIO_LD2);
+ stm32l4_configgpio(GPIO_LD2);
}
/****************************************************************************
@@ -181,9 +181,9 @@ void board_userled_initialize(void)
void board_userled(int led, bool ledon)
{
- if (led == 1)
+ if (led == BOARD_LD2)
{
- stm32_gpiowrite(GPIO_LD2, ldeon);
+ stm32l4_gpiowrite(GPIO_LD2, ledon);
}
}
@@ -193,10 +193,7 @@ void board_userled(int led, bool ledon)
void board_userled_all(uint8_t ledset)
{
- if (led == 1)
- {
- stm32_gpiowrite(GPIO_LD2, (ledset & BOARD_LD2_BIT) != 0);
- }
+ stm32l4_gpiowrite(GPIO_LD2, (ledset & BOARD_LD2_BIT) != 0);
}
/****************************************************************************
diff --git a/configs/stm32l476vg-disco/src/stm32_userleds.c b/configs/stm32l476vg-disco/src/stm32_userleds.c
index 4bee92bde81..f1b27fb26f5 100644
--- a/configs/stm32l476vg-disco/src/stm32_userleds.c
+++ b/configs/stm32l476vg-disco/src/stm32_userleds.c
@@ -192,11 +192,11 @@ void board_userled(int led, bool ledon)
switch (led)
{
case BOARD_LED_RED:
- stm32l4_gpiowrite(GPIO_LED_RED, ldeon);
+ stm32l4_gpiowrite(GPIO_LED_RED, ledon);
break;
case BOARD_LED_GRN:
- stm32l4_gpiowrite(GPIO_LED_GRN, ldeon);
+ stm32l4_gpiowrite(GPIO_LED_GRN, ledon);
break;
}
}
diff --git a/drivers/loop/losetup.c b/drivers/loop/losetup.c
index 32c2f4d4374..0690776e230 100644
--- a/drivers/loop/losetup.c
+++ b/drivers/loop/losetup.c
@@ -440,7 +440,7 @@ int losetup(FAR const char *devname, FAR const char *filename,
{
/* If that fails, then try to open the device read-only */
- fd = open(filename, O_RDWR);
+ fd = open(filename, O_RDONLY);
if (fd < 0)
{
ret = -get_errno();
diff --git a/drivers/mmcsd/mmcsd_sdio.c b/drivers/mmcsd/mmcsd_sdio.c
index 3d890287010..9cb491feb7d 100644
--- a/drivers/mmcsd/mmcsd_sdio.c
+++ b/drivers/mmcsd/mmcsd_sdio.c
@@ -1895,6 +1895,25 @@ static ssize_t mmcsd_writemultiple(FAR struct mmcsd_state_s *priv,
}
}
+ /* If Controller does not need DMA setup before the write then send CMD25
+ * now.
+ */
+
+ if ((priv->caps & SDIO_CAPS_DMABEFOREWRITE) == 0)
+ {
+ /* Send CMD25, WRITE_MULTIPLE_BLOCK, and verify that good R1 status
+ * is returned
+ */
+
+ mmcsd_sendcmdpoll(priv, MMCSD_CMD25, offset);
+ ret = mmcsd_recvR1(priv, MMCSD_CMD25);
+ if (ret != OK)
+ {
+ ferr("ERROR: mmcsd_recvR1 for CMD25 failed: %d\n", ret);
+ return ret;
+ }
+ }
+
/* Configure SDIO controller hardware for the write transfer */
SDIO_BLOCKSETUP(priv->dev, priv->blocksize, nblocks);
@@ -1923,24 +1942,30 @@ static ssize_t mmcsd_writemultiple(FAR struct mmcsd_state_s *priv,
priv->wrbusy = true;
- /* Send CMD25, WRITE_MULTIPLE_BLOCK, and verify that good R1 status
- * is returned
- */
+ /* If Controller needs DMA setup before write then only send CMD25 now. */
- mmcsd_sendcmdpoll(priv, MMCSD_CMD25, offset);
- ret = mmcsd_recvR1(priv, MMCSD_CMD25);
- if (ret != OK)
+ if ((priv->caps & SDIO_CAPS_DMABEFOREWRITE) != 0)
{
- ferr("ERROR: mmcsd_recvR1 for CMD25 failed: %d\n", ret);
- return ret;
+ /* Send CMD25, WRITE_MULTIPLE_BLOCK, and verify that good R1 status
+ * is returned
+ */
+
+ mmcsd_sendcmdpoll(priv, MMCSD_CMD25, offset);
+ ret = mmcsd_recvR1(priv, MMCSD_CMD25);
+ if (ret != OK)
+ {
+ ferr("ERROR: mmcsd_recvR1 for CMD25 failed: %d\n", ret);
+ return ret;
+ }
}
/* Wait for the transfer to complete */
- ret = mmcsd_eventwait(priv, SDIOWAIT_TIMEOUT | SDIOWAIT_ERROR, nblocks * MMCSD_BLOCK_WDATADELAY);
+ ret = mmcsd_eventwait(priv, SDIOWAIT_TIMEOUT | SDIOWAIT_ERROR,
+ nblocks * MMCSD_BLOCK_WDATADELAY);
if (ret != OK)
{
- ferr("ERROR: CMD18 transfer failed: %d\n", ret);
+ ferr("ERROR: CMD25 transfer failed: %d\n", ret);
return ret;
}
diff --git a/fs/procfs/fs_procfs.c b/fs/procfs/fs_procfs.c
index e269d873e3a..5b5801aa91a 100644
--- a/fs/procfs/fs_procfs.c
+++ b/fs/procfs/fs_procfs.c
@@ -77,6 +77,7 @@
****************************************************************************/
extern const struct procfs_operations proc_operations;
+extern const struct procfs_operations irq_operations;
extern const struct procfs_operations cpuload_operations;
extern const struct procfs_operations meminfo_operations;
extern const struct procfs_operations module_operations;
@@ -124,8 +125,12 @@ static const struct procfs_entry_s g_procfs_entries[] =
{ "cpuload", &cpuload_operations, PROCFS_FILE_TYPE },
#endif
+#ifdef CONFIG_SCHED_IRQMONITOR
+ { "irqs", &irq_operations, PROCFS_FILE_TYPE },
+#endif
+
#ifndef CONFIG_FS_PROCFS_EXCLUDE_MEMINFO
- { "meminfo", &meminfo_operations, PROCFS_FILE_TYPE },
+ { "meminfo", &meminfo_operations, PROCFS_FILE_TYPE },
#endif
#if defined(CONFIG_MODULE) && !defined(CONFIG_FS_PROCFS_EXCLUDE_MODULE)
@@ -133,15 +138,15 @@ static const struct procfs_entry_s g_procfs_entries[] =
#endif
#ifndef CONFIG_FS_PROCFS_EXCLUDE_BLOCKS
- { "fs/blocks", &mount_procfsoperations, PROCFS_FILE_TYPE },
+ { "fs/blocks", &mount_procfsoperations, PROCFS_FILE_TYPE },
#endif
#ifndef CONFIG_FS_PROCFS_EXCLUDE_MOUNT
- { "fs/mount", &mount_procfsoperations, PROCFS_FILE_TYPE },
+ { "fs/mount", &mount_procfsoperations, PROCFS_FILE_TYPE },
#endif
#ifndef CONFIG_FS_PROCFS_EXCLUDE_USAGE
- { "fs/usage", &mount_procfsoperations, PROCFS_FILE_TYPE },
+ { "fs/usage", &mount_procfsoperations, PROCFS_FILE_TYPE },
#endif
#if defined(CONFIG_FS_SMARTFS) && !defined(CONFIG_FS_PROCFS_EXCLUDE_SMARTFS)
diff --git a/fs/procfs/fs_procfsutil.c b/fs/procfs/fs_procfsutil.c
index 7a71ff18540..9dd4f536740 100644
--- a/fs/procfs/fs_procfsutil.c
+++ b/fs/procfs/fs_procfsutil.c
@@ -124,7 +124,7 @@ size_t procfs_memcpy(FAR const char *src, size_t srclen,
/* Handle the remaining offset */
srclen -= lnoffset;
- dest += lnoffset;
+ src += lnoffset;
*offset = 0;
/* Copy the line into the user destination buffer */
diff --git a/fs/smartfs/smartfs_utils.c b/fs/smartfs/smartfs_utils.c
index da37b922124..99bb8c16567 100644
--- a/fs/smartfs/smartfs_utils.c
+++ b/fs/smartfs/smartfs_utils.c
@@ -2072,7 +2072,7 @@ int smartfs_extendfile(FAR struct smartfs_mountpt_s *fs,
ret = OK;
errout_with_buffer:
-#ifdef CONFIG_SMARTFS_USE_SECTOR_BUFFER
+#ifndef CONFIG_SMARTFS_USE_SECTOR_BUFFER
/* Release the allocated buffer */
kmm_free(buffer);
diff --git a/include/nuttx/irq.h b/include/nuttx/irq.h
index 8f4ed3824f4..e5674d81c09 100644
--- a/include/nuttx/irq.h
+++ b/include/nuttx/irq.h
@@ -114,8 +114,8 @@ typedef uint32_t irq_mapped_t;
/* This struct defines the form of an interrupt service routine */
-typedef int (*xcpt_t)(int irq, FAR void *context, FAR void *arg);
-#endif
+typedef CODE int (*xcpt_t)(int irq, FAR void *context, FAR void *arg);
+#endif /* __ASSEMBLY__ */
/* Now include architecture-specific types */
diff --git a/include/nuttx/spi/spi.h b/include/nuttx/spi/spi.h
index 08b28e26255..b881e962571 100644
--- a/include/nuttx/spi/spi.h
+++ b/include/nuttx/spi/spi.h
@@ -70,8 +70,8 @@
* Name: SPI_LOCK
*
* Description:
- * On SPI busses where there are multiple devices, it will be necessary to
- * lock SPI to have exclusive access to the busses for a sequence of
+ * On SPI buses where there are multiple devices, it will be necessary to
+ * lock SPI to have exclusive access to the buses for a sequence of
* transfers. The bus should be locked before the chip is selected. After
* locking the SPI bus, the caller should then also call the setfrequency,
* setbits, and setmode methods to make sure that the SPI is properly
diff --git a/sched/Kconfig b/sched/Kconfig
index 6a50b93fe89..64af6daf108 100644
--- a/sched/Kconfig
+++ b/sched/Kconfig
@@ -623,6 +623,15 @@ endmenu # Pthread Options
menu "Performance Monitoring"
+config SCHED_IRQMONITOR
+ bool "Enable IRQ monitoring"
+ default n
+ depends on FS_PROCFS
+ ---help---
+ Enabling counting of interrupts from all interrupt sources. These
+ counts will be available in the mounted procfs file systems at the
+ top-level file, "irqs".
+
config SCHED_CPULOAD
bool "Enable CPU load monitoring"
default n
diff --git a/sched/clock/clock_systimer.c b/sched/clock/clock_systimer.c
index 1b134510922..e1d4440ab11 100644
--- a/sched/clock/clock_systimer.c
+++ b/sched/clock/clock_systimer.c
@@ -1,7 +1,7 @@
/****************************************************************************
* sched/clock/clock_systimer.c
*
- * Copyright (C) 2011, 2014-2016 Gregory Nutt. All rights reserved.
+ * Copyright (C) 2011, 2014-2016, 2018 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt
*
* Redistribution and use in source and binary forms, with or without
@@ -50,10 +50,15 @@
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
+
/* See nuttx/clock.h */
#undef clock_systimer
+/* 32-bit mask for 64-bit timer values */
+
+#define TIMER_MASK32 0x00000000ffffffff
+
/****************************************************************************
* Public Functions
****************************************************************************/
@@ -109,20 +114,34 @@ systime_t clock_systimer(void)
/* Convert to a 64- then a 32-bit value */
tmp = USEC2TICK(1000000 * (uint64_t)ts.tv_sec + (uint64_t)ts.tv_nsec / 1000);
- return (systime_t)(tmp & 0x00000000ffffffff);
+ return (systime_t)(tmp & TIMER_MASK32);
# endif /* CONFIG_SYSTEM_TIME64 */
#else /* CONFIG_SCHED_TICKLESS */
# ifdef CONFIG_SYSTEM_TIME64
- irqstate_t flags;
systime_t sample;
+ systime_t verify;
- /* 64-bit accesses are not atomic on most architectures. */
+ /* 64-bit accesses are not atomic on most architectures. The following
+ * loop samples the 64-bit timer twice and loops in the rare event that
+ * there was 32-bit rollover between samples.
+ *
+ * If there is no 32-bit rollover, then:
+ *
+ * - The MS 32-bits of each sample will be the same, and
+ * - The LS 32-bits of the second sample will be greater than or equal to
+ * the LS 32-bits for the first sample.
+ */
+
+ do
+ {
+ verify = g_system_timer;
+ sample = g_system_timer;
+ }
+ while ((sample & TIMER_MASK32) < (verify & TIMER_MASK32) ||
+ (sample & ~TIMER_MASK32) != (verify & ~TIMER_MASK32));
- flags = enter_critical_section();
- sample = g_system_timer;
- leave_critical_section(flags);
return sample;
# else /* CONFIG_SYSTEM_TIME64 */
diff --git a/sched/init/os_start.c b/sched/init/os_start.c
index 80fc944956e..9033189e639 100644
--- a/sched/init/os_start.c
+++ b/sched/init/os_start.c
@@ -115,7 +115,7 @@ volatile dq_queue_t g_readytorun;
* and
* - Tasks/threads that have not been assigned to a CPU.
*
- * Otherwise, the TCB will be reatined in an assigned task list,
+ * Otherwise, the TCB will be retained in an assigned task list,
* g_assignedtasks. As its name suggests, on 'g_assignedtasks queue for CPU
* 'n' would contain only tasks/threads that are assigned to CPU 'n'. Tasks/
* threads would be assigned a particular CPU by one of two mechanisms:
@@ -187,7 +187,7 @@ volatile dq_queue_t g_waitingforfill;
volatile dq_queue_t g_inactivetasks;
-/* These are lists of dayed memory deallocations that need to be handled
+/* These are lists of delayed memory deallocations that need to be handled
* within the IDLE loop or worker thread. These deallocations get queued
* by sched_kufree and sched_kfree() if the OS needs to deallocate memory
* while it is within an interrupt handler.
@@ -229,7 +229,7 @@ struct pidhash_s g_pidhash[CONFIG_MAX_TASKS];
/* This is a table of task lists. This table is indexed by the task stat
* enumeration type (tstate_t) and provides a pointer to the associated
* static task list (if there is one) as well as a a set of attribute flags
- * indicating properities of the list, for example, if the list is an
+ * indicating properties of the list, for example, if the list is an
* ordered list or not.
*/
@@ -311,7 +311,7 @@ uint8_t g_os_initstate; /* See enum os_initstate_e */
/****************************************************************************
* Private Data
****************************************************************************/
-/* This is an arry of task control block (TCB) for the IDLE thread of each
+/* This is an array of task control block (TCB) for the IDLE thread of each
* CPU. For the non-SMP case, this is a a single TCB; For the SMP case,
* there is one TCB per CPU. NOTE: The system boots on CPU0 into the IDLE
* task. The IDLE task later starts the other CPUs and spawns the user
diff --git a/sched/irq/Make.defs b/sched/irq/Make.defs
index 72636e3ea20..8ae2fde5c3e 100644
--- a/sched/irq/Make.defs
+++ b/sched/irq/Make.defs
@@ -1,7 +1,7 @@
############################################################################
# sched/irq/Make.defs
#
-# Copyright (C) 2014, 2016 Gregory Nutt. All rights reserved.
+# Copyright (C) 2014, 2016, 2018 Gregory Nutt. All rights reserved.
# Author: Gregory Nutt
#
# Redistribution and use in source and binary forms, with or without
@@ -44,6 +44,13 @@ else ifeq ($(CONFIG_SCHED_INSTRUMENTATION_CSECTION),y)
CSRCS += irq_csection.c
endif
+ifeq ($(CONFIG_SCHED_IRQMONITOR),y)
+CSRCS += irq_foreach.c
+ifeq ($(CONFIG_FS_PROCFS),y)
+CSRCS += irq_procfs.c
+endif
+endif
+
# Include irq build support
DEPPATH += --dep-path irq
diff --git a/sched/irq/irq.h b/sched/irq/irq.h
index ffb6e9859aa..ac38158f3cc 100644
--- a/sched/irq/irq.h
+++ b/sched/irq/irq.h
@@ -1,7 +1,8 @@
/****************************************************************************
* sched/irq/irq.h
*
- * Copyright (C) 2007, 2008, 2013-2014, 2017 Gregory Nutt. All rights reserved.
+ * Copyright (C) 2007, 2008, 2013-2014, 2017-2018 Gregory Nutt. All rights
+ * reserved.
* Author: Gregory Nutt
*
* Redistribution and use in source and binary forms, with or without
@@ -71,10 +72,26 @@
struct irq_info_s
{
- xcpt_t handler; /* Address of the interrupt handler */
- FAR void *arg; /* The argument provided to the interrupt handler. */
+ xcpt_t handler; /* Address of the interrupt handler */
+ FAR void *arg; /* The argument provided to the interrupt handler. */
+#ifdef CONFIG_SCHED_IRQMONITOR
+ systime_t start; /* Time interrupt attached */
+#ifdef CONFIG_HAVE_LONG_LONG
+ uint64_t count; /* Number of interrupts on this IRQ */
+#else
+ uint32_t mscount; /* Number of interrupts on this IRQ (MS) */
+ uint32_t lscount; /* Number of interrupts on this IRQ (LS) */
+#endif
+#endif
};
+#ifdef CONFIG_SCHED_IRQMONITOR
+/* This is the type of the callback from irq_foreach(). */
+
+typedef CODE int (*irq_foreach_t)(int irq, FAR struct irq_info_s *info,
+ FAR void *arg);
+#endif
+
/****************************************************************************
* Public Data
****************************************************************************/
@@ -180,6 +197,36 @@ int irq_unexpected_isr(int irq, FAR void *context, FAR void *arg);
bool irq_cpu_locked(int cpu);
#endif
+/****************************************************************************
+ * Name: irq_foreach
+ *
+ * Description:
+ * This function traverses the internal list of interrupts and provides
+ * information about each attached interrupt.
+ *
+ * Some caution may be necessary: If interrupts are disabled then the
+ * counts may change during the traversal. If pre-emption is enabled, then
+ * the traversed sequence may be widely separated in time.
+ *
+ * Input Parameters:
+ * callback - This function will be called for each attached interrupt
+ * along with the IRQ number, an instance of struct irq_info_s,
+ * and the caller provided argument
+ * args - This is an opaque argument provided with each call to the
+ * callback function.
+ *
+ * Returned Value:
+ * Zero (OK) is returned after callback has been invoked for all of
+ * the attached interrupts. The callback function may terminate the
+ * traversal at any time by returning a non-zero value. In that case,
+ * irq_foreach will return that non-zero value.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_SCHED_IRQMONITOR
+int irq_foreach(irq_foreach_t callback, FAR void *arg);
+#endif
+
#undef EXTERN
#ifdef __cplusplus
}
diff --git a/sched/irq/irq_attach.c b/sched/irq/irq_attach.c
index a55ba758e60..da03f094275 100644
--- a/sched/irq/irq_attach.c
+++ b/sched/irq/irq_attach.c
@@ -1,7 +1,8 @@
/****************************************************************************
* sched/irq/irq_attach.c
*
- * Copyright (C) 2007-2008, 2010, 2012, 2017 Gregory Nutt. All rights reserved.
+ * Copyright (C) 2007-2008, 2010, 2012, 2017-2018 Gregory Nutt. All rights
+ * reserved.
* Author: Gregory Nutt
*
* Redistribution and use in source and binary forms, with or without
@@ -115,6 +116,15 @@ int irq_attach(int irq, xcpt_t isr, FAR void *arg)
g_irqvector[ndx].handler = isr;
g_irqvector[ndx].arg = arg;
+#ifdef CONFIG_SCHED_IRQMONITOR
+ g_irqvector[ndx].start = clock_systimer();
+#ifdef CONFIG_HAVE_LONG_LONG
+ g_irqvector[ndx].count = 0;
+#else
+ g_irqvector[ndx].mscount = 0;
+ g_irqvector[ndx].lscount = 0;
+#endif
+#endif
leave_critical_section(flags);
ret = OK;
diff --git a/sched/irq/irq_dispatch.c b/sched/irq/irq_dispatch.c
index b311e8a2c11..ef78824213f 100644
--- a/sched/irq/irq_dispatch.c
+++ b/sched/irq/irq_dispatch.c
@@ -1,7 +1,7 @@
/****************************************************************************
* sched/irq/irq_dispatch.c
*
- * Copyright (C) 2007, 2008, 2017 Gregory Nutt. All rights reserved.
+ * Copyright (C) 2007, 2008, 2017-2018 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt
*
* Redistribution and use in source and binary forms, with or without
@@ -46,6 +46,33 @@
#include "irq/irq.h"
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#ifdef CONFIG_SCHED_IRQMONITOR
+# ifdef CONFIG_HAVE_LONG_LONG
+# define INCR_COUNT(ndx) \
+ do \
+ { \
+ g_irqvector[ndx].count++; \
+ } \
+ while (0)
+# else
+# define INCR_COUNT(ndx) \
+ do \
+ { \
+ if (++g_irqvector[ndx].lscount == 0) \
+ { \
+ g_irqvector[ndx].mscount++; \
+ } \
+ } \
+ while (0)
+# endif
+#else
+# define INCR_COUNT(ndx)
+#endif
+
/****************************************************************************
* Public Functions
****************************************************************************/
@@ -86,13 +113,14 @@ void irq_dispatch(int irq, FAR void *context)
{
vector = g_irqvector[ndx].handler;
arg = g_irqvector[ndx].arg;
+ INCR_COUNT(ndx);
}
#else
vector = g_irqvector[irq].handler;
arg = g_irqvector[irq].arg;
+ INCR_COUNT(irq);
#endif
}
-
#else
vector = irq_unexpected_isr;
arg = NULL;
diff --git a/sched/irq/irq_foreach.c b/sched/irq/irq_foreach.c
new file mode 100644
index 00000000000..731fcf706f5
--- /dev/null
+++ b/sched/irq/irq_foreach.c
@@ -0,0 +1,118 @@
+/****************************************************************************
+ * sched/irq/irq_foreach.c
+ *
+ * Copyright (C) 2018 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include
+
+#include
+#include
+
+#include
+
+#include "irq/irq.h"
+
+#ifdef CONFIG_SCHED_IRQMONITOR
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* This is the number of entries in the interrupt vector table */
+
+#ifdef CONFIG_ARCH_MINIMAL_VECTORTABLE
+# define TAB_SIZE CONFIG_ARCH_NUSER_INTERRUPTS
+#else
+# define TAB_SIZE NR_IRQS
+#endif
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: irq_foreach
+ *
+ * Description:
+ * This function traverses the internal list of interrupts and provides
+ * information about each attached interrupt.
+ *
+ * Some caution may be necessary: If interrupts are disabled then the
+ * counts may change during the traversal. If pre-emption is enabled, then
+ * the traversed sequence may be widely separated in time.
+ *
+ * Input Parameters:
+ * callback - This function will be called for each attached interrupt
+ * along with the IRQ number, an instance of struct irq_info_s,
+ * and the caller provided argument
+ * args - This is an opaque argument provided with each call to the
+ * callback function.
+ *
+ * Returned Value:
+ * Zero (OK) is returned after callback has been invoked for all of
+ * the attached interrupts. The callback function may terminate the
+ * traversal at any time by returning a non-zero value. In that case,
+ * irq_foreach will return that non-zero value.
+ *
+ ****************************************************************************/
+
+int irq_foreach(irq_foreach_t callback, FAR void *arg)
+{
+ int irq;
+ int ret;
+
+ DEBUGASSERT(callback != NULL);
+
+ /* Visit each interrupt in the interrupt table */
+
+ for (irq = 0; irq < TAB_SIZE; irq++)
+ {
+ if (g_irqvector[irq].handler != NULL &&
+ g_irqvector[irq].handler != irq_unexpected_isr)
+ {
+ ret = callback(irq, &g_irqvector[irq], arg);
+ if (ret != 0)
+ {
+ return ret;
+ }
+ }
+ }
+
+ return OK;
+}
+
+#endif /* CONFIG_SCHED_IRQMONITOR */
diff --git a/sched/irq/irq_initialize.c b/sched/irq/irq_initialize.c
index 18bbafc4b37..b2355f9a90d 100644
--- a/sched/irq/irq_initialize.c
+++ b/sched/irq/irq_initialize.c
@@ -1,7 +1,7 @@
/****************************************************************************
* sched/irq/irq_initialize.c
*
- * Copyright (C) 2007-2008, 2010 Gregory Nutt. All rights reserved.
+ * Copyright (C) 2007-2008, 2010, 2018 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt
*
* Redistribution and use in source and binary forms, with or without
@@ -89,5 +89,14 @@ void irq_initialize(void)
{
g_irqvector[i].handler = irq_unexpected_isr;
g_irqvector[i].arg = NULL;
+#ifdef CONFIG_SCHED_IRQMONITOR
+ g_irqvector[i].start = 0;
+#ifdef CONFIG_HAVE_LONG_LONG
+ g_irqvector[i].count = 0;
+#else
+ g_irqvector[i].mscount = 0;
+ g_irqvector[i].lscount = 0;
+#endif
+#endif
}
}
diff --git a/sched/irq/irq_procfs.c b/sched/irq/irq_procfs.c
new file mode 100644
index 00000000000..bbfb76df179
--- /dev/null
+++ b/sched/irq/irq_procfs.c
@@ -0,0 +1,443 @@
+/****************************************************************************
+ * sched/irq/irq_procfs.c
+ *
+ * Copyright (C) 2018 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+
+#include "irq/irq.h"
+
+#if !defined(CONFIG_DISABLE_MOUNTPOINT) && defined(CONFIG_FS_PROCFS)
+#ifdef CONFIG_SCHED_IRQMONITOR
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+/* Output format:
+ *
+ * 11111111112222222222333333333344
+ * 12345678901234567890123456789012345678901
+ *
+ * IRQ HANDLER ARGUMENT COUNT RATE
+ * DDD XXXXXXXX XXXXXXXX DDDDDDDDDD DDDD.DDD
+ *
+ * NOTE: This assumes that an address can be represented in 32-bits. In
+ * the typical configuration where CONFIG_HAVE_LONG_LONG=y, the COUNT field
+ * may not be wide enough.
+ */
+
+#define HDR_FMT "IRQ HANDLER ARGUMENT COUNT RATE\n"
+#define IRQ_FMT "%3u %08lx %08lx %10lu %4lu.%03lu\n"
+
+/* Determines the size of an intermediate buffer that must be large enough
+ * to handle the longest line generated by this logic (plus a couple of
+ * bytes).
+ */
+
+#define IRQ_LINELEN 44
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/* This structure describes one open "file" */
+
+struct irq_file_s
+{
+ struct procfs_file_s base; /* Base open file structure */
+ FAR char *buffer; /* User provided buffer */
+ size_t remaining; /* Number of available characters in buffer */
+ size_t ncopied; /* Number of characters in buffer */
+ off_t offset; /* Current file offset */
+ char line[IRQ_LINELEN]; /* Pre-allocated buffer for formatted lines */
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* irq_foreach() callback function */
+
+static int irq_callback(int irq, FAR struct irq_info_s *info,
+ FAR void *arg);
+
+/* File system methods */
+
+static int irq_open(FAR struct file *filep, FAR const char *relpath,
+ int oflags, mode_t mode);
+static int irq_close(FAR struct file *filep);
+static ssize_t irq_read(FAR struct file *filep, FAR char *buffer,
+ size_t buflen);
+static int irq_dup(FAR const struct file *oldp,
+ FAR struct file *newp);
+static int irq_stat(FAR const char *relpath, FAR struct stat *buf);
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+/* See fs_mount.c -- this structure is explicitly extern'ed there.
+ * We use the old-fashioned kind of initializers so that this will compile
+ * with any compiler.
+ */
+
+const struct procfs_operations irq_operations =
+{
+ irq_open, /* open */
+ irq_close, /* close */
+ irq_read, /* read */
+ NULL, /* write */
+
+ irq_dup, /* dup */
+
+ NULL, /* opendir */
+ NULL, /* closedir */
+ NULL, /* readdir */
+ NULL, /* rewinddir */
+
+ irq_stat /* stat */
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: irq_callback
+ ****************************************************************************/
+
+static int irq_callback(int irq, FAR struct irq_info_s *info,
+ FAR void *arg)
+{
+ FAR struct irq_file_s *irqfile = (FAR struct irq_file_s *)arg;
+ struct irq_info_s copy;
+ irqstate_t flags;
+ systime_t elapsed;
+ systime_t now;
+ size_t linesize;
+ size_t copysize;
+ unsigned long intpart;
+ unsigned long fracpart;
+ unsigned long count;
+
+ DEBUGASSERT(irqfile != NULL);
+
+ /* Take a snapshot and reset the counts */
+
+ flags = enter_critical_section();
+ memcpy(©, info, sizeof(struct irq_info_s));
+ now = clock_systimer();
+ info->start = now;
+#ifdef CONFIG_HAVE_LONG_LONG
+ info->count = 0;
+#else
+ info->mscount = 0;
+ info->lscount = 0;
+#endif
+ leave_critical_section(flags);
+
+ /* Don't bother if count == 0 */
+
+ if (copy.count == 0)
+ {
+ return 0;
+ }
+
+ /* Calculate the interrupt rate from the interrupt count and the elapsed
+ * time.
+ *
+ * REVISIT: If these counts have not been samples and reset in a long time
+ * then the following will likely overflow.
+ */
+
+ elapsed = now - copy.start;
+
+#ifdef CONFIG_HAVE_LONG_LONG
+ /* elapsed = - , units=clock ticks
+ * rate = * TICKS_PER_SEC / elapsed
+ */
+
+ intpart = (unsigned int)((copy.count * TICK_PER_SEC) / elapsed);
+ if (intpart >= 10000)
+ {
+ intpart = 9999;
+ fracpart = 999;
+ }
+ else
+ {
+ uint64_t intcount = (uint64_t)intpart * elapsed / TICK_PER_SEC;
+ fracpart = (unsigned int)
+ (((copy.count - intcount) * TICK_PER_SEC * 1000) / elapsed);
+ }
+
+ /* Make sure that the count is representable with snprintf format */
+
+ if (copy.count > ULONG_MAX)
+ {
+ count = ULONG_MAX;
+ }
+ else
+ {
+ count = (unsigned long)copy.count;
+ }
+
+#else
+# error Missing logic
+#endif
+
+ /* Output information about this interrupt */
+
+ linesize = snprintf(irqfile->line, IRQ_LINELEN, IRQ_FMT,
+ (unsigned int)irq,
+ (unsigned long)((uintptr_t)copy.handler),
+ (unsigned long)((uintptr_t)copy.arg),
+ count, intpart, fracpart);
+
+ copysize = procfs_memcpy(irqfile->line, linesize, irqfile->buffer,
+ irqfile->remaining, &irqfile->offset);
+
+ irqfile->ncopied += copysize;
+ irqfile->buffer += copysize;
+ irqfile->remaining -= copysize;
+
+ /* Return a non-zero value to stop the traversal if the user-provided
+ * buffer is full.
+ */
+
+ if (irqfile->remaining > 0)
+ {
+ return 0;
+ }
+ else
+ {
+ return 1;
+ }
+}
+
+/****************************************************************************
+ * Name: irq_open
+ ****************************************************************************/
+
+static int irq_open(FAR struct file *filep, FAR const char *relpath,
+ int oflags, mode_t mode)
+{
+ FAR struct irq_file_s *irqfile;
+
+ finfo("Open '%s'\n", relpath);
+
+ /* PROCFS is read-only. Any attempt to open with any kind of write
+ * access is not permitted.
+ *
+ * REVISIT: Write-able proc files could be quite useful.
+ */
+
+ if ((oflags & O_WRONLY) != 0 || (oflags & O_RDONLY) == 0)
+ {
+ ferr("ERROR: Only O_RDONLY supported\n");
+ return -EACCES;
+ }
+
+ /* "irqs" is the only acceptable value for the relpath */
+
+ if (strcmp(relpath, "irqs") != 0)
+ {
+ ferr("ERROR: relpath is '%s'\n", relpath);
+ return -ENOENT;
+ }
+
+ /* Allocate a container to hold the file attributes */
+
+ irqfile = (FAR struct irq_file_s *)kmm_zalloc(sizeof(struct irq_file_s));
+ if (!irqfile)
+ {
+ ferr("ERROR: Failed to allocate file attributes\n");
+ return -ENOMEM;
+ }
+
+ /* Save the attributes as the open-specific state in filep->f_priv */
+
+ filep->f_priv = (FAR void *)irqfile;
+ return OK;
+}
+
+/****************************************************************************
+ * Name: irq_close
+ ****************************************************************************/
+
+static int irq_close(FAR struct file *filep)
+{
+ FAR struct irq_file_s *irqfile;
+
+ /* Recover our private data from the struct file instance */
+
+ irqfile = (FAR struct irq_file_s *)filep->f_priv;
+ DEBUGASSERT(irqfile);
+
+ /* Release the file attributes structure */
+
+ kmm_free(irqfile);
+ filep->f_priv = NULL;
+ return OK;
+}
+
+/****************************************************************************
+ * Name: irq_read
+ ****************************************************************************/
+
+static ssize_t irq_read(FAR struct file *filep, FAR char *buffer,
+ size_t buflen)
+{
+ FAR struct irq_file_s *irqfile;
+ size_t linesize;
+ size_t copysize;
+
+ finfo("buffer=%p buflen=%d\n", buffer, (int)buflen);
+
+ /* Recover our private data from the struct file instance */
+
+ irqfile = (FAR struct irq_file_s *)filep->f_priv;
+ DEBUGASSERT(irqfile);
+
+ /* Save the file offset and the user buffer information */
+
+ irqfile->offset = filep->f_pos;
+ irqfile->buffer = buffer;
+ irqfile->remaining = buflen;
+
+ /* The first line to output is the header */
+
+ linesize = snprintf(irqfile->line, IRQ_LINELEN, HDR_FMT);
+
+ copysize = procfs_memcpy(irqfile->line, linesize, irqfile->buffer,
+ irqfile->remaining, &irqfile->offset);
+
+ irqfile->ncopied = copysize;
+ irqfile->buffer += copysize;
+ irqfile->remaining -= copysize;
+
+ /* Now traverse the list of attached interrupts, generating output for
+ * each.
+ */
+
+ (void)irq_foreach(irq_callback, (FAR void *)irqfile);
+
+ /* Update the file position */
+
+ filep->f_pos += irqfile->ncopied;
+ return irqfile->ncopied;
+}
+
+/****************************************************************************
+ * Name: irq_dup
+ *
+ * Description:
+ * Duplicate open file data in the new file structure.
+ *
+ ****************************************************************************/
+
+static int irq_dup(FAR const struct file *oldp, FAR struct file *newp)
+{
+ FAR struct irq_file_s *oldattr;
+ FAR struct irq_file_s *newattr;
+
+ finfo("Dup %p->%p\n", oldp, newp);
+
+ /* Recover our private data from the old struct file instance */
+
+ oldattr = (FAR struct irq_file_s *)oldp->f_priv;
+ DEBUGASSERT(oldattr);
+
+ /* Allocate a new container to hold the task and attribute selection */
+
+ newattr = (FAR struct irq_file_s *)kmm_malloc(sizeof(struct irq_file_s));
+ if (!newattr)
+ {
+ ferr("ERROR: Failed to allocate file attributes\n");
+ return -ENOMEM;
+ }
+
+ /* The copy the file attributes from the old attributes to the new */
+
+ memcpy(newattr, oldattr, sizeof(struct irq_file_s));
+
+ /* Save the new attributes in the new file structure */
+
+ newp->f_priv = (FAR void *)newattr;
+ return OK;
+}
+
+/****************************************************************************
+ * Name: irq_stat
+ *
+ * Description: Return information about a file or directory
+ *
+ ****************************************************************************/
+
+static int irq_stat(const char *relpath, struct stat *buf)
+{
+ /* "irqs" is the only acceptable value for the relpath */
+
+ if (strcmp(relpath, "irqs") != 0)
+ {
+ ferr("ERROR: relpath is '%s'\n", relpath);
+ return -ENOENT;
+ }
+
+ /* "irqs" is the name for a read-only file */
+
+ memset(buf, 0, sizeof(struct stat));
+ buf->st_mode = S_IFREG | S_IROTH | S_IRGRP | S_IRUSR;
+ return OK;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+#endif /* CONFIG_SCHED_IRQMONITOR */
+#endif /* !CONFIG_DISABLE_MOUNTPOINT && CONFIG_FS_PROCFS */
diff --git a/sched/pthread/pthread_setschedparam.c b/sched/pthread/pthread_setschedparam.c
index 3c04cfb0232..f5ce5c5391d 100644
--- a/sched/pthread/pthread_setschedparam.c
+++ b/sched/pthread/pthread_setschedparam.c
@@ -1,7 +1,8 @@
/****************************************************************************
* sched/pthread/pthread_setschedparam.c
*
- * Copyright (C) 2007, 2008, 2012, 2015 Gregory Nutt. All rights reserved.
+ * Copyright (C) 2007, 2008, 2012, 2015, 2018 Gregory Nutt. All rights
+ * reserved.
* Author: Gregory Nutt
*
* Redistribution and use in source and binary forms, with or without
@@ -105,10 +106,6 @@ int pthread_setschedparam(pthread_t thread, int policy,
sinfo("thread ID=%d policy=%d param=0x%p\n", thread, policy, param);
- /* Set the errno to some non-zero value (failsafe) */
-
- set_errno(EINVAL);
-
/* Let sched_setscheduler do all of the work */
ret = sched_setscheduler((pid_t)thread, policy, param);
diff --git a/sched/sched/sched.h b/sched/sched/sched.h
index eea2a3b1c2c..d083dc6a59d 100644
--- a/sched/sched/sched.h
+++ b/sched/sched/sched.h
@@ -1,7 +1,7 @@
/****************************************************************************
* sched/sched/sched.h
*
- * Copyright (C) 2007-2014, 2016 Gregory Nutt. All rights reserved.
+ * Copyright (C) 2007-2014, 2016, 2018 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt
*
* Redistribution and use in source and binary forms, with or without
@@ -63,6 +63,10 @@
* tasks built into the design).
*/
+#if CONFIG_MAX_TASKS & (CONFIG_MAX_TASKS - 1)
+# error CONFIG_MAX_TASKS must be power of 2
+#endif
+
#define MAX_TASKS_MASK (CONFIG_MAX_TASKS-1)
#define PIDHASH(pid) ((pid) & MAX_TASKS_MASK)
diff --git a/sched/semaphore/sem_recover.c b/sched/semaphore/sem_recover.c
index bccb904e07b..6305f0d35e8 100644
--- a/sched/semaphore/sem_recover.c
+++ b/sched/semaphore/sem_recover.c
@@ -105,7 +105,7 @@ void nxsem_recover(FAR struct tcb_s *tcb)
nxsem_canceled(tcb, sem);
/* And increment the count on the semaphore. This releases the count
- * that was taken by sem_post(). This count decremented the semaphore
+ * that was taken by sem_wait(). This count decremented the semaphore
* count to negative and caused the thread to be blocked in the first
* place.
*/
diff --git a/sched/task/task_create.c b/sched/task/task_create.c
index a1d07e1d8ec..2cc8c1a9118 100644
--- a/sched/task/task_create.c
+++ b/sched/task/task_create.c
@@ -103,11 +103,11 @@ static int thread_create(FAR const char *name, uint8_t ttype, int priority,
goto errout;
}
+#ifdef HAVE_TASK_GROUP
/* Allocate a new task group with privileges appropriate for the parent
* thread type.
*/
-#ifdef HAVE_TASK_GROUP
ret = group_allocate(tcb, ttype);
if (ret < 0)
{
@@ -157,9 +157,9 @@ static int thread_create(FAR const char *name, uint8_t ttype, int priority,
(void)task_argsetup(tcb, name, argv);
+#ifdef HAVE_TASK_GROUP
/* Now we have enough in place that we can join the group */
-#ifdef HAVE_TASK_GROUP
ret = group_initialize(tcb);
if (ret < 0)
{
diff --git a/sched/task/task_setcanceltype.c b/sched/task/task_setcanceltype.c
index b7536f46258..3c08c5d3206 100644
--- a/sched/task/task_setcanceltype.c
+++ b/sched/task/task_setcanceltype.c
@@ -52,7 +52,7 @@
****************************************************************************/
/****************************************************************************
- * Name: task_setcancelstate
+ * Name: task_setcanceltype
*
* Description:
* The task_setcanceltype() function atomically both sets the calling
diff --git a/sched/wdog/wd_delete.c b/sched/wdog/wd_delete.c
index a497c1146e0..7b56bede466 100644
--- a/sched/wdog/wd_delete.c
+++ b/sched/wdog/wd_delete.c
@@ -1,7 +1,8 @@
/****************************************************************************
* sched/wdog/wd_delete.c
*
- * Copyright (C) 2007-2009, 2014, 2016 Gregory Nutt. All rights reserved.
+ * Copyright (C) 2007-2009, 2014, 2016, 2018 Gregory Nutt. All rights
+ * reserved.
* Author: Gregory Nutt
*
* Redistribution and use in source and binary forms, with or without
@@ -113,9 +114,7 @@ int wd_delete(WDOG_ID wdog)
sched_kfree(wdog);
}
- /* This was a pre-allocated timer. This function should not be called for
- * statically allocated timers.
- */
+ /* Check if this is pre-allocated timer. */
else if (!WDOG_ISSTATIC(wdog))
{
@@ -129,6 +128,13 @@ int wd_delete(WDOG_ID wdog)
leave_critical_section(flags);
}
+ /* This function should not be called for statically allocated timers. */
+
+ else
+ {
+ leave_critical_section(flags);
+ }
+
/* Return success */
return OK;
|