aboutsummaryrefslogtreecommitdiffstats
path: root/os
diff options
context:
space:
mode:
Diffstat (limited to 'os')
-rw-r--r--os/hal/include/spi.h15
-rw-r--r--os/hal/src/spi.c65
-rw-r--r--os/hal/templates/spi_lld.h6
3 files changed, 84 insertions, 2 deletions
diff --git a/os/hal/include/spi.h b/os/hal/include/spi.h
index b09e33089..e6fbe7c90 100644
--- a/os/hal/include/spi.h
+++ b/os/hal/include/spi.h
@@ -39,7 +39,16 @@
/*===========================================================================*/
/**
- * @brief Enables the mutual exclusion APIs on the SPI bus.
+ * @brief Enables the @p spiWait() API.
+ * @note Disabling this option saves both code and data space.
+ */
+#if !defined(SPI_USE_WAIT) || defined(__DOXYGEN__)
+#define SPI_USE_WAIT TRUE
+#endif
+
+/**
+ * @brief Enables the @p spiAcquireBus() and @p spiReleaseBus() APIs.
+ * @note Disabling this option saves both code and data space.
*/
#if !defined(SPI_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__)
#define SPI_USE_MUTUAL_EXCLUSION TRUE
@@ -218,6 +227,10 @@ extern "C" {
void spiExchange(SPIDriver *spip, size_t n, const void *txbuf, void *rxbuf);
void spiSend(SPIDriver *spip, size_t n, const void *txbuf);
void spiReceive(SPIDriver *spip, size_t n, void *rxbuf);
+#if SPI_USE_WAIT
+ void _spi_wakeup(SPIDriver *spip, mag_t msg);
+ msg_t spiWait(SPIDriver *spip);
+#endif /* SPI_USE_WAIT */
#if SPI_USE_MUTUAL_EXCLUSION
void spiAcquireBus(SPIDriver *spip);
void spiReleaseBus(SPIDriver *spip);
diff --git a/os/hal/src/spi.c b/os/hal/src/spi.c
index cd5857aa9..75589c736 100644
--- a/os/hal/src/spi.c
+++ b/os/hal/src/spi.c
@@ -66,11 +66,16 @@ void spiInit(void) {
void spiObjectInit(SPIDriver *spip) {
spip->spd_state = SPI_STOP;
+#if SPI_USE_WAIT
+ spip->spd_thread = NULL;
+#endif /* SPI_USE_WAIT */
+#if SPI_USE_MUTUAL_EXCLUSION
#if CH_USE_MUTEXES
chMtxInit(&spip->spd_mutex);
-#elif CH_USE_SEMAPHORES
+#else
chSemInit(&spip->spd_semaphore, 1);
#endif
+#endif /* SPI_USE_MUTUAL_EXCLUSION */
spip->spd_config = NULL;
}
@@ -296,6 +301,64 @@ void spiReceive(SPIDriver *spip, size_t n, void *rxbuf) {
chSysUnlock();
}
+#if SPI_USE_WAIT || defined(__DOXYGEN__)
+/**
+ * @brief Awakens the thread waiting for operation completion, if any.
+ *
+ * @param[in] spip pointer to the @p SPIDriver object
+ *
+ * @notapi
+ */
+void _spi_wakeup(SPIDriver *spip) {
+
+ if (spip->spd_thread != NULL) {
+ Thread *tp = spip->spd_thread;
+ spip->spd_thread = NULL;
+ tp->p_u.rdymsg = RDY_RESET;
+ chSchReadyI(tp);
+ }
+}
+
+/**
+ * @brief Wait for operation completion.
+ * @details This function waits for the driver to complete the current
+ * operation, if an operation is not running when the function is
+ * invoked then it immediately returns.
+ * @note No more than one thread can wait on a SPI driver using
+ * this function.
+ *
+ * @param[in] spip pointer to the @p SPIDriver object
+ * @return The wait status.
+ * @retval RDY_OK There was not operation running when the function
+ * has been invoked.
+ * @retval RDY_RESET The operation completed.
+ */
+msg_t spiWait(SPIDriver *spip) {
+ msg_t msg;
+
+ chDbgCheck(spip != NULL, "spiWait");
+
+ chSysLock();
+ chDbgAssert((spip->spd_state == SPI_READY) ||
+ (spip->spd_state == SPI_SELECTED) ||
+ (spip->spd_state == SPI_ACTIVE) ||
+ (spip->spd_state == SPI_SYNC),
+ "spiUnselect(), #1",
+ "invalid state");
+ chDbgAssert(spip->spd_thread == NULL, "spiWait(), #3", "already waiting");
+ if ((spip->spd_state == SPI_ACTIVE) || (spip->spd_state == SPI_SYNC)) {
+ spip->spd_thread = chThdSelf();
+ chSchGoSleepS(spip->spd_thread, THD_STATE_SUSPENDED);
+ msg = chThdSelf()->p_u.rdymsg;
+ }
+ else
+ msg = RDY_OK;
+ chSysUnlock();
+ return msg;
+}
+
+#endif /* SPI_USE_WAIT */
+
#if SPI_USE_MUTUAL_EXCLUSION || defined(__DOXYGEN__)
/**
* @brief Gains exclusive access to the SPI bus.
diff --git a/os/hal/templates/spi_lld.h b/os/hal/templates/spi_lld.h
index 152784701..2aa63b455 100644
--- a/os/hal/templates/spi_lld.h
+++ b/os/hal/templates/spi_lld.h
@@ -77,6 +77,12 @@ typedef struct {
* @brief Driver state.
*/
spistate_t spd_state;
+#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__)
/**