aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--demos/ARM7-LPC214x-FATFS-GCC/Makefile2
-rw-r--r--demos/ARM7-LPC214x-FATFS-GCC/main.c2
-rw-r--r--os/hal/platforms/LPC214x/lpc214x.h1
-rw-r--r--os/hal/platforms/LPC214x/spi_lld.c173
-rw-r--r--os/hal/platforms/LPC214x/spi_lld.h94
-rw-r--r--readme.txt4
6 files changed, 222 insertions, 54 deletions
diff --git a/demos/ARM7-LPC214x-FATFS-GCC/Makefile b/demos/ARM7-LPC214x-FATFS-GCC/Makefile
index 99ff790e9..17f023c4f 100644
--- a/demos/ARM7-LPC214x-FATFS-GCC/Makefile
+++ b/demos/ARM7-LPC214x-FATFS-GCC/Makefile
@@ -5,7 +5,7 @@
# Compiler options here.
ifeq ($(USE_OPT),)
- USE_OPT = -O2 -ggdb -fomit-frame-pointer -mabi=apcs-gnu -falign-functions=16
+ USE_OPT = -O0 -ggdb -fomit-frame-pointer -mabi=apcs-gnu -falign-functions=16
endif
# C++ specific options here (added to USE_OPT).
diff --git a/demos/ARM7-LPC214x-FATFS-GCC/main.c b/demos/ARM7-LPC214x-FATFS-GCC/main.c
index 80d383356..92c4563e0 100644
--- a/demos/ARM7-LPC214x-FATFS-GCC/main.c
+++ b/demos/ARM7-LPC214x-FATFS-GCC/main.c
@@ -43,6 +43,7 @@ static bool_t fs_ready = FALSE;
/* Maximum speed SPI configuration (18MHz, CPHA=0, CPOL=0).*/
static SPIConfig hs_spicfg = {
+ NULL,
IOPORT1,
PA_SSEL1,
CR0_DSS8BIT | CR0_FRFSPI | CR0_CLOCKRATE(0),
@@ -52,6 +53,7 @@ static SPIConfig hs_spicfg = {
/* Low speed SPI configuration (281.250KHz, CPHA=0, CPOL=0).*/
static SPIConfig ls_spicfg = {
+ NULL,
IOPORT1,
PA_SSEL1,
CR0_DSS8BIT | CR0_FRFSPI | CR0_CLOCKRATE(0),
diff --git a/os/hal/platforms/LPC214x/lpc214x.h b/os/hal/platforms/LPC214x/lpc214x.h
index 66c288028..f2ddac376 100644
--- a/os/hal/platforms/LPC214x/lpc214x.h
+++ b/os/hal/platforms/LPC214x/lpc214x.h
@@ -390,6 +390,7 @@ typedef struct {
#define SSPMIS (SSPBase->SSP_MIS)
#define SSPICR (SSPBase->SSP_ICR)
+#define CR0_DSSMASK 0x0F
#define CR0_DSS4BIT 3
#define CR0_DSS5BIT 4
#define CR0_DSS6BIT 5
diff --git a/os/hal/platforms/LPC214x/spi_lld.c b/os/hal/platforms/LPC214x/spi_lld.c
index d829c3d62..04dafb93d 100644
--- a/os/hal/platforms/LPC214x/spi_lld.c
+++ b/os/hal/platforms/LPC214x/spi_lld.c
@@ -28,13 +28,13 @@
#include "ch.h"
#include "hal.h"
-#if CH_HAL_USE_SPI || defined(__DOXYGEN__)
+#if LPC214x_SPI_USE_SSP || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver exported variables. */
/*===========================================================================*/
-#if USE_LPC214x_SPI1 || defined(__DOXYGEN__)
+#if LPC214x_SPI_USE_SSP || defined(__DOXYGEN__)
/** @brief SPI1 driver identifier.*/
SPIDriver SPID1;
#endif
@@ -48,38 +48,92 @@ SPIDriver SPID1;
/*===========================================================================*/
/**
- * @brief Synchronous SSP transfer.
+ * @brief Preloads the transmit FIFO.
*
- * @param[in] n number of bytes to be exchanged
- * @param[in] txbuf the pointer to the transmit buffer or @p NULL
- * @param[out] rxbuf the pointer to the receive buffer or @p NULL
+ * @param[in] spip pointer to the @p SPIDriver object
*/
-static void rw8(size_t n, const uint8_t *txbuf, uint8_t *rxbuf) {
- size_t ntx = n;
-
- while (n > 0) {
- uint32_t sr = SSPBase->SSP_SR;
- if (sr & SR_RNE) {
- uint8_t w = SSPBase->SSP_DR;
- if (rxbuf != NULL)
- *rxbuf++ = w;
- n--;
- continue; /* Priority over transmission. */
+static void ssp_fifo_preload(SPIDriver *spip) {
+ SSP *ssp = spip->spd_ssp;
+ uint32_t n = spip->spd_txcnt > LPC214x_SSP_FIFO_DEPTH ?
+ LPC214x_SSP_FIFO_DEPTH : spip->spd_txcnt;
+
+ while(((ssp->SSP_SR & SR_TNF) != 0) && (n > 0)) {
+ if (spip->spd_txptr != NULL) {
+ if ((ssp->SSP_CR0 & CR0_DSSMASK) > CR0_DSS8BIT)
+ ssp->SSP_DR = *(uint16_t *)spip->spd_txptr++;
+ else
+ ssp->SSP_DR = *(uint8_t *)spip->spd_txptr++;
}
- if ((ntx > 0) && (sr & SR_TNF)) {
- if (txbuf != NULL)
- SSPBase->SSP_DR = *txbuf++;
+ else
+ ssp->SSP_DR = 0xFFFFFFFF;
+ n--;
+ spip->spd_txcnt--;
+ }
+}
+
+#if defined(__GNUC__)
+__attribute__((noinline))
+#endif
+/**
+ * @brief Common IRQ handler.
+ *
+ * @param[in] spip pointer to the @p SPIDriver object
+ */
+static void serve_interrupt(SPIDriver *spip) {
+ SSP *ssp = spip->spd_ssp;
+
+ if ((ssp->SSP_MIS & MIS_ROR) != 0) {
+ /* The overflow condition should never happen because priority is given
+ to receive but a hook macro is provided anyway...*/
+ LPC214x_SPI_SSP_ERROR_HOOK();
+ }
+ ssp->SSP_ICR = ICR_RT | ICR_ROR;
+ while ((ssp->SSP_SR & SR_RNE) != 0) {
+ if (spip->spd_rxptr != NULL) {
+ if ((ssp->SSP_CR0 & CR0_DSSMASK) > CR0_DSS8BIT)
+ *(uint16_t *)spip->spd_rxptr++ = ssp->SSP_DR;
else
- SSPBase->SSP_DR = 0xFFFFFFFF;
- ntx--;
+ *(uint8_t *)spip->spd_rxptr++ = ssp->SSP_DR;
+ }
+ else
+ (void)ssp->SSP_DR;
+ if (--spip->spd_rxcnt == 0) {
+ chDbgAssert(spip->spd_txcnt == 0,
+ "chSemResetI(), #1", "counter out of synch");
+ /* Stops the IRQ sources.*/
+ ssp->SSP_IMSC = 0;
+ /* Portable SPI ISR code defined in the high level driver, note, it is
+ a macro.*/
+ _spi_isr_code(spip);
+ return;
}
}
+ ssp_fifo_preload(spip);
+ if (spip->spd_txcnt == 0)
+ ssp->SSP_IMSC = IMSC_ROR | IMSC_RT | IMSC_RX;
}
/*===========================================================================*/
/* Driver interrupt handlers. */
/*===========================================================================*/
+#if LPC214x_SPI_USE_SSP || defined(__DOXYGEN__)
+/**
+ * @brief SPI1 interrupt handler.
+ *
+ * @isr
+ */
+CH_IRQ_HANDLER(SPI1IrqHandler) {
+
+ CH_IRQ_PROLOGUE();
+
+ serve_interrupt(&SPID1);
+ VICVectAddr = 0;
+
+ CH_IRQ_EPILOGUE();
+}
+#endif
+
/*===========================================================================*/
/* Driver exported functions. */
/*===========================================================================*/
@@ -91,8 +145,10 @@ static void rw8(size_t n, const uint8_t *txbuf, uint8_t *rxbuf) {
*/
void spi_lld_init(void) {
-#if USE_LPC214x_SPI1
+#if LPC214x_SPI_USE_SSP
spiObjectInit(&SPID1);
+ SPID1.spd_ssp = SSPBase;
+ SetVICVector(SPI1IrqHandler, LPC214x_SPI_SSP_IRQ_PRIORITY, SOURCE_SPI1);
#endif
}
@@ -107,16 +163,22 @@ void spi_lld_start(SPIDriver *spip) {
if (spip->spd_state == SPI_STOP) {
/* Clock activation.*/
- PCONP = (PCONP & PCALL) | PCSPI1;
+#if LPC214x_SPI_USE_SSP
+ if (&SPID1 == spip) {
+ PCONP = (PCONP & PCALL) | PCSPI1;
+ VICIntEnable = INTMASK(SOURCE_SPI1);
+ }
+#endif
}
/* Configuration.*/
SSPBase->SSP_CR1 = 0;
/* Emptying the receive FIFO, it happens to not be empty while debugging.*/
- while (SSPBase->SSP_SR & SR_RNE)
- (void) SSPBase->SSP_DR;
- SSPBase->SSP_CR0 = spip->spd_config->spc_cr0;
- SSPBase->SSP_CPSR = spip->spd_config->spc_cpsr;
- SSPBase->SSP_CR1 = spip->spd_config->spc_cr1 | CR1_SSE;
+ while (spip->spd_ssp->SSP_SR & SR_RNE)
+ (void) spip->spd_ssp->SSP_DR;
+ spip->spd_ssp->SSP_ICR = ICR_RT | ICR_ROR;
+ spip->spd_ssp->SSP_CR0 = spip->spd_config->spc_cr0;
+ spip->spd_ssp->SSP_CPSR = spip->spd_config->spc_cpsr;
+ spip->spd_ssp->SSP_CR1 = spip->spd_config->spc_cr1 | CR1_SSE;
}
/**
@@ -129,6 +191,12 @@ void spi_lld_start(SPIDriver *spip) {
void spi_lld_stop(SPIDriver *spip) {
if (spip->spd_state != SPI_STOP) {
+#if LPC214x_SPI_USE_SSP
+ if (&SPID1 == spip) {
+ PCONP = (PCONP & PCALL) & ~PCSPI1;
+ VICIntEnClear = INTMASK(SOURCE_SPI1);
+ }
+#endif
SSPBase->SSP_CR1 = 0;
SSPBase->SSP_CR0 = 0;
SSPBase->SSP_CPSR = 0;
@@ -174,14 +242,20 @@ void spi_lld_unselect(SPIDriver *spip) {
*/
void spi_lld_ignore(SPIDriver *spip, size_t n) {
- (void)spip;
- rw8(n, NULL, NULL);
+ spip->spd_rxptr = NULL;
+ spip->spd_txptr = NULL;
+ spip->spd_rxcnt = spip->spd_txcnt = n;
+ ssp_fifo_preload(spip);
+ spip->spd_ssp->SSP_IMSC = IMSC_ROR | IMSC_RT | IMSC_TX | IMSC_RX;
}
/**
* @brief Exchanges data on the SPI bus.
- * @details This function performs a simultaneous transmit/receive operation.
- * @note The buffers are organized as uint8_t arrays.
+ * @details This asynchronous function starts a simultaneous transmit/receive
+ * operation.
+ * @post At the end of the operation the configured callback is invoked.
+ * @note The buffers are organized as uint8_t arrays for data sizes below or
+ * equal to 8 bits else it is organized as uint16_t arrays.
*
* @param[in] spip pointer to the @p SPIDriver object
* @param[in] n number of words to be exchanged
@@ -193,13 +267,19 @@ void spi_lld_ignore(SPIDriver *spip, size_t n) {
void spi_lld_exchange(SPIDriver *spip, size_t n,
const void *txbuf, void *rxbuf) {
- (void)spip;
- rw8(n, txbuf, rxbuf);
+ spip->spd_rxptr = rxbuf;
+ spip->spd_txptr = txbuf;
+ spip->spd_rxcnt = spip->spd_txcnt = n;
+ ssp_fifo_preload(spip);
+ spip->spd_ssp->SSP_IMSC = IMSC_ROR | IMSC_RT | IMSC_TX | IMSC_RX;
}
/**
- * @brief Sends data ever the SPI bus.
- * @note The buffers are organized as uint8_t arrays.
+ * @brief Sends data over the SPI bus.
+ * @details This asynchronous function starts a transmit operation.
+ * @post At the end of the operation the configured callback is invoked.
+ * @note The buffers are organized as uint8_t arrays for data sizes below or
+ * equal to 8 bits else it is organized as uint16_t arrays.
*
* @param[in] spip pointer to the @p SPIDriver object
* @param[in] n number of words to send
@@ -209,13 +289,19 @@ void spi_lld_exchange(SPIDriver *spip, size_t n,
*/
void spi_lld_send(SPIDriver *spip, size_t n, const void *txbuf) {
- (void)spip;
- rw8(n, txbuf, NULL);
+ spip->spd_rxptr = NULL;
+ spip->spd_txptr = txbuf;
+ spip->spd_rxcnt = spip->spd_txcnt = n;
+ ssp_fifo_preload(spip);
+ spip->spd_ssp->SSP_IMSC = IMSC_ROR | IMSC_RT | IMSC_TX | IMSC_RX;
}
/**
* @brief Receives data from the SPI bus.
- * @note The buffers are organized as uint8_t arrays.
+ * @details This asynchronous function starts a receive operation.
+ * @post At the end of the operation the configured callback is invoked.
+ * @note The buffers are organized as uint8_t arrays for data sizes below or
+ * equal to 8 bits else it is organized as uint16_t arrays.
*
* @param[in] spip pointer to the @p SPIDriver object
* @param[in] n number of words to receive
@@ -225,8 +311,11 @@ void spi_lld_send(SPIDriver *spip, size_t n, const void *txbuf) {
*/
void spi_lld_receive(SPIDriver *spip, size_t n, void *rxbuf) {
- (void)spip;
- rw8(n, NULL, rxbuf);
+ spip->spd_rxptr = rxbuf;
+ spip->spd_txptr = NULL;
+ spip->spd_rxcnt = spip->spd_txcnt = n;
+ ssp_fifo_preload(spip);
+ spip->spd_ssp->SSP_IMSC = IMSC_ROR | IMSC_RT | IMSC_TX | IMSC_RX;
}
#endif /* CH_HAL_USE_SPI */
diff --git a/os/hal/platforms/LPC214x/spi_lld.h b/os/hal/platforms/LPC214x/spi_lld.h
index d3d271cf0..57d02d4de 100644
--- a/os/hal/platforms/LPC214x/spi_lld.h
+++ b/os/hal/platforms/LPC214x/spi_lld.h
@@ -34,32 +34,77 @@
/* Driver constants. */
/*===========================================================================*/
+/**
+ * @brief Hardware FIFO depth.
+ */
+#define LPC214x_SSP_FIFO_DEPTH 8
+
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
/**
- * @brief SPI1 (SSP) driver enable switch.
- * @details If set to @p TRUE the support for SPI0 is included.
+ * @brief SPI1 driver enable switch.
+ * @details If set to @p TRUE the support for SSP is included.
* @note The default is @p TRUE.
*/
-#if !defined(USE_LPC214x_SPI1) || defined(__DOXYGEN__)
-#define USE_LPC214x_SPI1 TRUE
+#if !defined(LPC214x_SPI_USE_SSP) || defined(__DOXYGEN__)
+#define LPC214x_SPI_USE_SSP TRUE
+#endif
+
+/**
+ * @brief SSP interrupt priority level setting.
+ */
+#if !defined(STM32_SPI_SPI1_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define LPC214x_SPI_SSP_IRQ_PRIORITY 4
+#endif
+
+/**
+ * @brief Overflow error hook.
+ * @details The default action is to stop the system.
+ */
+#if !defined(LPC214x_SPI_SSP_ERROR_HOOK) || defined(__DOXYGEN__)
+#define LPC214x_SPI_SSP_ERROR_HOOK() chSysHalt()
#endif
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
+#if !LPC214x_SPI_USE_SSP
+#error "SPI driver activated but no SPI peripheral assigned"
+#endif
+
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
/**
+ * @brief Type of a structure representing an SPI driver.
+ */
+typedef struct SPIDriver SPIDriver;
+
+/**
+ * @brief SPI notification callback type.
+ *
+ * @param[in] spip pointer to the @p SPIDriver object triggering the
+ * callback
+ */
+typedef void (*spicallback_t)(SPIDriver *spip);
+
+/**
* @brief Driver configuration structure.
*/
typedef struct {
/**
+ * @brief Operation complete callback or @p NULL.
+ * @note In order to use synchronous functions this field must be set to
+ * @p NULL, callbacks and synchronous operations are mutually
+ * exclusive.
+ */
+ spicallback_t spc_endcb;
+ /* End of the mandatory fields.*/
+ /**
* @brief The chip select line port.
*/
ioportid_t spc_ssport;
@@ -84,11 +129,21 @@ typedef struct {
/**
* @brief Structure representing a SPI driver.
*/
-typedef struct {
+struct SPIDriver {
/**
* @brief Driver state.
*/
spistate_t spd_state;
+ /**
+ * @brief Current configuration data.
+ */
+ const SPIConfig *spd_config;
+#if SPI_USE_WAIT || defined(__DOXYGEN__)
+ /**
+ * @brief Waiting thread.
+ */
+ Thread *spd_thread;
+#endif /* SPI_USE_WAIT */
#if SPI_USE_MUTUAL_EXCLUSION || defined(__DOXYGEN__)
#if CH_USE_MUTEXES || defined(__DOXYGEN__)
/**
@@ -99,12 +154,31 @@ typedef struct {
Semaphore spd_semaphore;
#endif
#endif /* SPI_USE_MUTUAL_EXCLUSION */
+#if defined(SPI_DRIVER_EXT_FIELDS)
+ SPI_DRIVER_EXT_FIELDS
+#endif
+ /* End of the mandatory fields.*/
/**
- * @brief Current configuration data.
+ * @brief Pointer to the SSP registers block.
*/
- const SPIConfig *spd_config;
- /* End of the mandatory fields.*/
-} SPIDriver;
+ SSP *spd_ssp;
+ /**
+ * @brief Number of bytes yet to be received.
+ */
+ uint32_t spd_rxcnt;
+ /**
+ * @brief Receive pointer or @p NULL.
+ */
+ void *spd_rxptr;
+ /**
+ * @brief Number of bytes yet to be transmitted.
+ */
+ uint32_t spd_txcnt;
+ /**
+ * @brief Transmit pointer or @p NULL.
+ */
+ const void *spd_txptr;
+};
/*===========================================================================*/
/* Driver macros. */
@@ -114,7 +188,7 @@ typedef struct {
/* External declarations. */
/*===========================================================================*/
-#if USE_LPC214x_SPI1 && !defined(__DOXYGEN__)
+#if LPC214x_SPI_USE_SSP && !defined(__DOXYGEN__)
extern SPIDriver SPID1;
#endif
diff --git a/readme.txt b/readme.txt
index 7c83635bd..cb59ba980 100644
--- a/readme.txt
+++ b/readme.txt
@@ -73,7 +73,7 @@
(backported to 2.0.6).
- FIX: Incorrect AT91SAM7X initialization, thanks Leszek (bug 3075354)
(backported to 2.0.5).
-- FIX: Fixed race condition in function chSchGoSleepTimeoutS, thanks Balázs
+- FIX: Fixed race condition in function chSchGoSleepTimeoutS(), thanks Balázs
(bug 3074984)(backported to 2.0.5).
- FIX: Fixed race condition in threads creation (bug 3069854)(backported
to 2.0.5).
@@ -114,6 +114,8 @@
- NEW: Added to the UART driver the capability to return the number of
not yet transferred frames when stopping an operation.
- NEW: Added more compile-time checks to the various STM32 device drivers.
+- NEW: Improved LPC214x SPI driver, now it uses IRQs and implements the
+ new SPI device driver model.
- NEW: Added a simple STM32 ADC demo under ./testhal/STM32/ADC.
- NEW: Added a simple STM32 CAN demo under ./testhal/STM32/CAN.
- NEW: Added a simple STM32 PWM demo under ./testhal/STM32/PWM.