diff options
author | gdisirio <gdisirio@35acf78f-673a-0410-8e92-d51de3d6d3f4> | 2010-10-12 15:19:15 +0000 |
---|---|---|
committer | gdisirio <gdisirio@35acf78f-673a-0410-8e92-d51de3d6d3f4> | 2010-10-12 15:19:15 +0000 |
commit | 935e2fb27f56a3b81d4161d65e116e9da4fe441c (patch) | |
tree | af91647e95a1e6ad8879bf28b6cac2921814c10f | |
parent | c5053410867ea8538a918c4593075db04adaebca (diff) | |
download | ChibiOS-935e2fb27f56a3b81d4161d65e116e9da4fe441c.tar.gz ChibiOS-935e2fb27f56a3b81d4161d65e116e9da4fe441c.tar.bz2 ChibiOS-935e2fb27f56a3b81d4161d65e116e9da4fe441c.zip |
git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@2250 35acf78f-673a-0410-8e92-d51de3d6d3f4
-rw-r--r-- | os/hal/hal.dox | 160 | ||||
-rw-r--r-- | os/hal/include/adc.h | 83 | ||||
-rw-r--r-- | os/hal/include/spi.h | 119 | ||||
-rw-r--r-- | os/hal/platforms/STM32/adc_lld.h | 19 | ||||
-rw-r--r-- | os/hal/platforms/STM32/spi_lld.c | 16 | ||||
-rw-r--r-- | os/hal/platforms/STM32/spi_lld.h | 13 | ||||
-rw-r--r-- | os/hal/src/adc.c | 207 | ||||
-rw-r--r-- | os/hal/src/mmc_spi.c | 30 | ||||
-rw-r--r-- | os/hal/src/spi.c | 234 | ||||
-rw-r--r-- | os/hal/templates/adc_lld.h | 19 | ||||
-rw-r--r-- | os/hal/templates/spi_lld.h | 11 | ||||
-rw-r--r-- | readme.txt | 17 | ||||
-rw-r--r-- | testhal/STM32/SPI/main.c | 8 |
13 files changed, 473 insertions, 463 deletions
diff --git a/os/hal/hal.dox b/os/hal/hal.dox index 5a6cbb7cc..45d133014 100644 --- a/os/hal/hal.dox +++ b/os/hal/hal.dox @@ -239,24 +239,23 @@ rankdir="LR";
node [shape=circle, fontname=Helvetica, fontsize=8, fixedsize="true", width="0.9", height="0.9"];
edge [fontname=Helvetica, fontsize=8];
+
stop [label="SPI_STOP\nLow Power"];
uninit [label="SPI_UNINIT", style="bold"];
ready [label="SPI_READY\nClock Enabled"];
- selected [label="SPI_SELECTED\nSlave Selected"];
active [label="SPI_ACTIVE\nBus Active"];
- sync [label="SPI_SYNC\nSynchronization"];
- uninit -> stop [label="spiInit()", constraint=false];
- stop -> ready [label="spiStart()"];
- ready -> ready [label="spiUnselect()\nspiStart()\nspiWait()"];
- ready -> stop [label="spiStop()"];
- stop -> stop [label="spiStop()"];
- ready -> selected [label="spiSelect()"];
- selected -> selected [label="spiSelect()\nspiWait()"];
- selected -> ready [label="spiUnselect()"];
- selected -> active [label="spiIgnore()\nspiExchange()\nspiSend()\nspiReceive()"];
- active -> selected [label="spiWait()\n>spc_endcb<"];
- ready -> sync [label="spiSynchronize()"];
- sync -> ready [label="spiWait()\n>spc_endcb<"];
+ complete [label="SPI_COMPLETE\nComplete"];
+
+ uninit -> stop [label="\n spiInit()", constraint=false];
+ stop -> ready [label="\nspiStart()"];
+ ready -> ready [label="\nspiSelect()\nspiUnselect()\nspiStart()"];
+ ready -> stop [label="\nspiStop()"];
+ stop -> stop [label="\nspiStop()"];
+ ready -> active [label="\nspiStartXXXI() (async)\nspiXXX() (sync)"];
+ active -> ready [label="\nsync return"];
+ active -> complete [label="\nasync callback\n>spc_endcb<"];
+ complete -> active [label="\nspiStartXXXI() (async)\nthen\ncallback return"];
+ complete -> ready [label="\ncallback return"];
}
* @else
* @dot
@@ -264,24 +263,23 @@ rankdir="LR";
node [shape=circle, fontname=Helvetica, fontsize=8, fixedsize="true", width="0.9", height="0.9"];
edge [fontname=Helvetica, fontsize=8];
+
stop [label="SPI_STOP\nLow Power"];
uninit [label="SPI_UNINIT", style="bold"];
ready [label="SPI_READY\nClock Enabled"];
- selected [label="SPI_SELECTED\nSlave Selected"];
active [label="SPI_ACTIVE\nBus Active"];
- sync [label="SPI_SYNC\nSynchronization"];
- uninit -> stop [label="spiInit()", constraint=false];
- stop -> ready [label="spiStart()"];
- ready -> ready [label="spiUnselect()\nspiStart()\nspiWait()"];
- ready -> stop [label="spiStop()"];
- stop -> stop [label="spiStop()"];
- ready -> selected [label="spiSelect()"];
- selected -> selected [label="spiSelect()\nspiWait()"];
- selected -> ready [label="spiUnselect()"];
- selected -> active [label="spiIgnore()\nspiExchange()\nspiSend()\nspiReceive()"];
- active -> selected [label="spiWait()\n>spc_endcb<"];
- ready -> sync [label="spiSynchronize()"];
- sync -> ready [label="spiWait()\n>spc_endcb<"];
+ complete [label="SPI_COMPLETE\nComplete"];
+
+ uninit -> stop [label="\n spiInit()", constraint=false];
+ stop -> ready [label="\nspiStart()"];
+ ready -> ready [label="\nspiSelect()\nspiUnselect()\nspiStart()"];
+ ready -> stop [label="\nspiStop()"];
+ stop -> stop [label="\nspiStop()"];
+ ready -> active [label="\nspiStartXXX() (async)\nspiXXX() (sync)"];
+ active -> ready [label="\nsync return"];
+ active -> complete [label="\nasync callback\n>spc_endcb<"];
+ complete -> active [label="\nspiStartXXXI() (async)\nthen\ncallback return"];
+ complete -> ready [label="\ncallback return"];
}
* @enddot
* @endif
@@ -320,59 +318,95 @@ digraph example {
size="5, 7";
rankdir="LR";
- node [shape=circle, fontname=Helvetica, fontsize=8, fixedsize="true", width="0.8", height="0.8"];
+ node [shape=circle, fontname=Helvetica, fontsize=8, fixedsize="true", width="0.9", height="0.9"];
edge [fontname=Helvetica, fontsize=8];
+
stop [label="ADC_STOP\nLow Power"];
uninit [label="ADC_UNINIT", style="bold"];
ready [label="ADC_READY\nClock Enabled"];
- running [label="ADC_RUNNING"];
- complete [label="ADC_COMPLETE"];
- uninit -> stop [label="adcInit()", constraint=false];
- stop -> ready [label="adcStart()"];
- ready -> ready [label="adcStart()"];
- ready -> ready [label="adcWaitConversion()"];
- ready -> stop [label="adcStop()"];
- stop -> stop [label="adcStop()"];
- ready -> running [label="adcStartConversion()"];
- running -> ready [label="adcStopConversion()"];
- running -> complete [label="End of Conversion"];
- complete -> running [label="adcStartConversion()"];
- complete -> ready [label="adcStopConversion()"];
- complete -> ready [label="adcWaitConversion()"];
- complete -> stop [label="adcStop()"];
+ active [label="ADC_ACTIVE\nConverting"];
+ complete [label="ADC_COMPLETE\nComplete"];
+
+ uninit -> stop [label="\n adcInit()", constraint=false];
+ stop -> ready [label="\nadcStart()"];
+ ready -> ready [label="\nadcStart()\nadcStopConversion()"];
+ ready -> stop [label="\nadcStop()"];
+ stop -> stop [label="\nadcStop()"];
+ ready -> active [label="\nadcStartConversion() (async)\nadcConvert() (sync)"];
+ active -> ready [label="\nadcStopConversion()\nsync return"];
+ active -> complete [label="\nasync callback\n>acg_endcb<"];
+ complete -> active [label="\nadcStartConversionI()\nthen\ncallback return()"];
+ complete -> ready [label="\nadcStopConversionI()\nthen\ncallback return"];
}
* @enddot
* @else
* @dot
digraph example {
rankdir="LR";
- node [shape=circle, fontname=Helvetica, fontsize=8, fixedsize="true", width="0.8", height="0.8"];
+ node [shape=circle, fontname=Helvetica, fontsize=8, fixedsize="true", width="0.9", height="0.9"];
edge [fontname=Helvetica, fontsize=8];
+
stop [label="ADC_STOP\nLow Power"];
uninit [label="ADC_UNINIT", style="bold"];
ready [label="ADC_READY\nClock Enabled"];
- running [label="ADC_RUNNING"];
- complete [label="ADC_COMPLETE"];
- uninit -> stop [label="adcInit()", constraint=false];
- stop -> ready [label="adcStart()"];
- ready -> ready [label="adcStart()"];
- ready -> ready [label="adcWaitConversion()"];
- ready -> stop [label="adcStop()"];
- stop -> stop [label="adcStop()"];
- ready -> running [label="adcStartConversion()"];
- running -> ready [label="adcStopConversion()"];
- running -> complete [label="End of Conversion"];
- complete -> running [label="adcStartConversion()"];
- complete -> ready [label="adcStopConversion()"];
- complete -> ready [label="adcWaitConversion()"];
- complete -> stop [label="adcStop()"];
+ active [label="ADC_ACTIVE\nConverting"];
+ complete [label="ADC_COMPLETE\nComplete"];
+
+ uninit -> stop [label="\n adcInit()", constraint=false];
+ stop -> ready [label="\nadcStart()"];
+ ready -> ready [label="\nadcStart()\nadcStopConversion()"];
+ ready -> stop [label="\nadcStop()"];
+ stop -> stop [label="\nadcStop()"];
+ ready -> active [label="\nadcStartConversion() (async)\nadcConvert() (sync)"];
+ active -> ready [label="\nadcStopConversion()\nsync return"];
+ active -> complete [label="\nasync callback\n>acg_endcb<"];
+ complete -> active [label="\nadcStartConversionI()\nthen\ncallback return()"];
+ complete -> ready [label="\nadcStopConversionI()\nthen\ncallback return"];
}
* @enddot
* @endif
*
- * The driver supports a continuous conversion mode with circular buffer,
- * callback functions allow to process the converted data in real time.
- * Please refer to the documentation of the function @p adcStartConversion().
+ * @section adc_2 ADC Operations
+ * The ADC driver is quite complex, an explanation of the terminology and of
+ * the operational details follows.
+ *
+ * @subsection adc_2_1 ADC Conversion Groups
+ * The ADC Conversion Group is the objects that specifies a physical
+ * conversion operation. This structure contains some standard fields and
+ * several implementation-dependent fields.<br>
+ * The standard fields define the CG mode, the number of channels belonging
+ * to the CG and the optional callbacks.<br>
+ * The implementation-dependent fields specify the physical ADC operation
+ * mode, the analog channels belonging to the group and any other
+ * implementation-specific setting. Usually the extra fields just mirror
+ * the physical ADC registers, please refer to the vendor's MCU Reference
+ * Manual for details about the available settings. Details are also available
+ * into the documentation of the ADC low level drivers and in the various
+ * sample applications.
+ *
+ * @subsection adc_2_2 ADC Conversion Modes
+ * The driver supports several conversion modes:
+ * - <b>One Shot</b>, the driver performs a single group conversion then stops.
+ * - <b>Linear Buffer</b>, the driver performs a series of group conversions
+ * then stops. This mode is like a one shot conversion repeated N times,
+ * the buffer pointer increases after each conversion. The buffer is
+ * organized as an S(CG)*N samples matrix, when S(CG) is the conversion
+ * group size (number of channels) and N is the buffer depth (number of
+ * repeated conversions).
+ * - <b>Circular Buffer</b>, much like the linear mode but the operation does
+ * not stop when the buffer is filled, it is automatically restarted
+ * with the buffer pointer wrapping back to the buffer base.
+ * .
+ * @subsection adc_2_3 ADC Callbacks
+ * The driver is able to invoke callbacks during the conversion process. A
+ * callback is invoked when the operation has been completed or, in circular
+ * mode, when the buffer has been filled and the operation is restarted. In
+ * linear and circular modes a callback is also invoked when the buffer is
+ * half filled.<br>
+ * The "half filled" and "filled" callbacks in circular mode allow to
+ * implement "streaming processing" of the sampled data, while the driver is
+ * busy filling one half of the buffer the application can process the
+ * other half, this allows for continuous interleaved operations.
*
* @ingroup IO
*/
diff --git a/os/hal/include/adc.h b/os/hal/include/adc.h index 7549ea515..dab90b477 100644 --- a/os/hal/include/adc.h +++ b/os/hal/include/adc.h @@ -39,12 +39,21 @@ /*===========================================================================*/
/**
- * @brief Inclusion of the @p adcWaitConversion() function.
+ * @brief Enables synchronous APIs.
+ * @note Disabling this option saves both code and data space.
*/
#if !defined(ADC_USE_WAIT) || defined(__DOXYGEN__)
#define ADC_USE_WAIT TRUE
#endif
+/**
+ * @brief Enables the @p adcAcquireBus() and @p adcReleaseBus() APIs.
+ * @note Disabling this option saves both code and data space.
+ */
+#if !defined(ADC_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__)
+#define ADC_USE_MUTUAL_EXCLUSION TRUE
+#endif
+
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
@@ -61,11 +70,11 @@ * @brief Driver state machine possible states.
*/
typedef enum {
- ADC_UNINIT = 0, /**< @brief Not initialized. */
- ADC_STOP = 1, /**< @brief Stopped. */
- ADC_READY = 2, /**< @brief Ready. */
- ADC_RUNNING = 3, /**< @brief Conversion running. */
- ADC_COMPLETE = 4 /**< @brief Conversion complete.*/
+ ADC_UNINIT = 0, /**< Not initialized. */
+ ADC_STOP = 1, /**< Stopped. */
+ ADC_READY = 2, /**< Ready. */
+ ADC_ACTIVE = 3, /**< Converting. */
+ ADC_COMPLETE = 4 /**< Conversion complete. */
} adcstate_t;
#include "adc_lld.h"
@@ -74,6 +83,49 @@ typedef enum { /* Driver macros. */
/*===========================================================================*/
+#if ADC_USE_WAIT || defined(__DOXYGEN__)
+/**
+ * @brief Resumes a thread waiting for a conversion completion.
+ * + * @param[in] adcp pointer to the @p ADCDriver object
+ *
+ * @notapi
+ */
+#define _adc_reset_i(adcp) { \
+ if ((adcp)->ad_thread != NULL) { \
+ Thread *tp = (adcp)->ad_thread; \
+ (adcp)->ad_thread = NULL; \
+ tp->p_u.rdymsg = RDY_RESET; \
+ chSchReadyI(tp); \
+ } \
+}
+
+/**
+ * @brief Resumes a thread waiting for a conversion completion.
+ *
+ * @param[in] adcp pointer to the @p ADCDriver object
+ *
+ * @notapi
+ */
+#define _adc_reset_s(adcp) { \
+ if ((adcp)->ad_thread != NULL) { \
+ Thread *tp = (adcp)->ad_thread; \
+ (adcp)->ad_thread = NULL; \
+ chSchWakeupS(tp, RDY_RESET); \
+ } \
+}
+
+#else /* !ADC_USE_WAIT */
+
+#define _adc_reset_i(adcp)
+
+#define _adc_reset_s(adcp)
+
+#define _adc_isr_code(adcp) { \
+}
+
+#endif /* !ADC_USE_WAIT */
+
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
@@ -85,19 +137,26 @@ extern "C" { void adcObjectInit(ADCDriver *adcp);
void adcStart(ADCDriver *adcp, const ADCConfig *config);
void adcStop(ADCDriver *adcp);
- bool_t adcStartConversion(ADCDriver *adcp,
+ void adcStartConversion(ADCDriver *adcp,
+ const ADCConversionGroup *grpp,
+ adcsample_t *samples,
+ size_t depth);
+ void adcStartConversionI(ADCDriver *adcp,
const ADCConversionGroup *grpp,
adcsample_t *samples,
size_t depth);
- bool_t adcStartConversionI(ADCDriver *adcp,
- const ADCConversionGroup *grpp,
- adcsample_t *samples,
- size_t depth);
void adcStopConversion(ADCDriver *adcp);
void adcStopConversionI(ADCDriver *adcp);
#if ADC_USE_WAIT
- msg_t adcWaitConversion(ADCDriver *adcp, systime_t timeout);
+ msg_t adcConvert(ADCDriver *adcp,
+ const ADCConversionGroup *grpp,
+ adcsample_t *samples,
+ size_t depth);
#endif
+#if ADC_USE_MUTUAL_EXCLUSION || defined(__DOXYGEN__)
+ void adcAcquireBus(ADCDriver *adcp);
+ void adcReleaseBus(ADCDriver *adcp);
+#endif /* ADC_USE_MUTUAL_EXCLUSION */
#ifdef __cplusplus
}
#endif
diff --git a/os/hal/include/spi.h b/os/hal/include/spi.h index cb13fa605..fbd26c207 100644 --- a/os/hal/include/spi.h +++ b/os/hal/include/spi.h @@ -39,7 +39,7 @@ /*===========================================================================*/
/**
- * @brief Enables the "wait" APIs.
+ * @brief Enables synchronous APIs.
* @note Disabling this option saves both code and data space.
*/
#if !defined(SPI_USE_WAIT) || defined(__DOXYGEN__)
@@ -70,12 +70,11 @@ * @brief Driver state machine possible states.
*/
typedef enum {
- SPI_UNINIT = 0, /**< @brief Not initialized. */
- SPI_STOP = 1, /**< @brief Stopped. */
- SPI_READY = 2, /**< @brief Ready. */
- SPI_SYNC= 3, /**< @brief Synchronizing. */
- SPI_SELECTED = 4, /**< @brief Slave selected. */
- SPI_ACTIVE = 5 /**< @brief Exchanging data. */
+ SPI_UNINIT = 0, /**< Not initialized. */
+ SPI_STOP = 1, /**< Stopped. */
+ SPI_READY = 2, /**< Ready. */
+ SPI_ACTIVE = 3, /**< Exchanging data. */
+ SPI_COMPLETE = 4 /**< Asynchronous operation complete. */
} spistate_t;
#include "spi_lld.h"
@@ -89,10 +88,9 @@ typedef enum { *
* @param[in] spip pointer to the @p SPIDriver object
*
- * @api
+ * @iclass
*/
#define spiSelectI(spip) { \
- (spip)->spd_state = SPI_SELECTED; \
spi_lld_select(spip); \
}
@@ -102,35 +100,13 @@ typedef enum { *
* @param[in] spip pointer to the @p SPIDriver object
*
- * @api
+ * @iclass
*/
#define spiUnselectI(spip) { \
- (spip)->spd_state = SPI_READY; \
spi_lld_unselect(spip); \
}
/**
- * @brief Emits a train of clock pulses on the SPI bus.
- * @details This asynchronous function starts the emission of a train of
- * clock pulses without asserting any slave.
- * @note This functionality is not usually required by the SPI protocol
- * but it is required by initialization procedure of MMC/SD cards
- * in SPI mode.
- * @post At the end of the operation the configured callback is invoked.
- *
- * @param[in] spip pointer to the @p SPIDriver object
- * @param[in] n number of words to be clocked. The number of pulses
- * is equal to the number of words multiplied to the
- * configured word size in bits.
- *
- * @api
- */
-#define spiSynchronizeI(spip, n) { \
- (spip)->spd_state = SPI_SYNC; \
- spi_lld_ignore(spip, n); \
-}
-
-/**
* @brief Ignores data on the SPI bus.
* @details This asynchronous function starts the transmission of a series of
* idle words on the SPI bus and ignores the received data.
@@ -141,9 +117,9 @@ typedef enum { * @param[in] spip pointer to the @p SPIDriver object
* @param[in] n number of words to be ignored
*
- * @api
+ * @iclass
*/
-#define spiIgnoreI(spip, n) { \
+#define spiStartIgnoreI(spip, n) { \
(spip)->spd_state = SPI_ACTIVE; \
spi_lld_ignore(spip, n); \
}
@@ -163,9 +139,9 @@ typedef enum { * @param[in] txbuf the pointer to the transmit buffer
* @param[out] rxbuf the pointer to the receive buffer
*
- * @api
+ * @iclass
*/
-#define spiExchangeI(spip, n, txbuf, rxbuf) { \
+#define spiStartExchangeI(spip, n, txbuf, rxbuf) { \
(spip)->spd_state = SPI_ACTIVE; \
spi_lld_exchange(spip, n, txbuf, rxbuf); \
}
@@ -183,9 +159,9 @@ typedef enum { * @param[in] n number of words to send
* @param[in] txbuf the pointer to the transmit buffer
*
- * @api
+ * @iclass
*/
-#define spiSendI(spip, n, txbuf) { \
+#define spiStartSendI(spip, n, txbuf) { \
(spip)->spd_state = SPI_ACTIVE; \
spi_lld_send(spip, n, txbuf); \
}
@@ -203,16 +179,21 @@ typedef enum { * @param[in] n number of words to receive
* @param[out] rxbuf the pointer to the receive buffer
*
- * @api
+ * @iclass
*/
-#define spiReceiveI(spip, n, rxbuf) { \
+#define spiStartReceiveI(spip, n, rxbuf) { \
(spip)->spd_state = SPI_ACTIVE; \
spi_lld_receive(spip, n, rxbuf); \
}
#if SPI_USE_WAIT || defined(__DOXYGEN__)
/**
- * @brief Awakens the thread waiting for operation completion, if any.
+ * @brief Common ISR code.
+ * @details This code handles the portable part of the ISR code:
+ * - Callback invocation.
+ * - Waiting thread wakeup, if any.
+ * - Driver state transitions.
+ * .
* @note This macro is meant to be used in the low level drivers
* implementation only.
*
@@ -220,14 +201,23 @@ typedef enum { *
* @notapi
*/
-#define _spi_wakeup(spip) { \
- chSysLockFromIsr(); \
- if ((spip)->spd_thread != NULL) { \
- Thread *tp = (spip)->spd_thread; \
- (spip)->spd_thread = NULL; \
- chSchReadyI(tp); \
+#define _spi_isr_code(spip) { \
+ if (spip->spd_config->spc_endcb) { \
+ spip->spd_state = SPI_COMPLETE; \
+ spip->spd_config->spc_endcb(spip); \
+ if (spip->spd_state == SPI_COMPLETE) \
+ spip->spd_state = SPI_READY; \
+ } \
+ else { \
+ spip->spd_state = SPI_READY; \
+ chSysLockFromIsr(); \
+ if ((spip)->spd_thread != NULL) { \
+ Thread *tp = (spip)->spd_thread; \
+ (spip)->spd_thread = NULL; \
+ chSchReadyI(tp); \
+ } \
+ chSysUnlockFromIsr(); \
} \
- chSysUnlockFromIsr(); \
}
/**
@@ -235,24 +225,31 @@ typedef enum { * @details This function waits for the driver to complete the current
* operation.
* @pre An operation must be running while the function is invoked.
- * @post On exit the SPI driver is ready to accept more commands.
* @note No more than one thread can wait on a SPI driver using
* this function.
*
* @param[in] spip pointer to the @p SPIDriver object
*
- * @sclass
+ * @notapi
*/
-#define spiWaitS(spip) { \
+#define _spi_wait(spip) { \
chDbgAssert((spip)->spd_thread == NULL, \
- "spiWaitS(), #1", "already waiting"); \
+ "_spi_wait(), #1", "already waiting"); \
(spip)->spd_thread = chThdSelf(); \
chSchGoSleepS(THD_STATE_SUSPENDED); \
}
#else /* !SPI_USE_WAIT */
-/* No wakeup when wait functions are disabled.*/
-#define _spi_wakeup(spip)
+#define _spi_isr_code(spip) { \
+ if (spip->spd_config->spc_endcb) { \
+ spip->spd_state = SPI_COMPLETE; \
+ spip->spd_config->spc_endcb(spip); \
+ if (spip->spd_state == SPI_COMPLETE) \
+ spip->spd_state = SPI_READY; \
+ } \
+ else \
+ spip->spd_state = SPI_READY; \
+}
#endif /* !SPI_USE_WAIT */
@@ -269,18 +266,16 @@ extern "C" { void spiStop(SPIDriver *spip);
void spiSelect(SPIDriver *spip);
void spiUnselect(SPIDriver *spip);
- void spiSynchronize(SPIDriver *spip, size_t n);
+ void spiStartIgnore(SPIDriver *spip, size_t n);
+ void spiStartExchange(SPIDriver *spip, size_t n,
+ const void *txbuf, void *rxbuf);
+ void spiStartSend(SPIDriver *spip, size_t n, const void *txbuf);
+ void spiStartReceive(SPIDriver *spip, size_t n, void *rxbuf);
+#if SPI_USE_WAIT
void spiIgnore(SPIDriver *spip, size_t n);
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 spiWait(SPIDriver *spip);
- void spiSynchronizeWait(SPIDriver *spip, size_t n);
- void spiIgnoreWait(SPIDriver *spip, size_t n);
- void spiExchangeWait(SPIDriver *spip, size_t n, const void *txbuf, void *rxbuf);
- void spiSendWait(SPIDriver *spip, size_t n, const void *txbuf);
- void spiReceiveWait(SPIDriver *spip, size_t n, void *rxbuf);
#endif /* SPI_USE_WAIT */
#if SPI_USE_MUTUAL_EXCLUSION
void spiAcquireBus(SPIDriver *spip);
diff --git a/os/hal/platforms/STM32/adc_lld.h b/os/hal/platforms/STM32/adc_lld.h index a72ce67f3..b1b1a7840 100644 --- a/os/hal/platforms/STM32/adc_lld.h +++ b/os/hal/platforms/STM32/adc_lld.h @@ -148,8 +148,11 @@ typedef struct { adc_channels_num_t acg_num_channels;
/**
* @brief Callback function associated to the group 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.
*/
- adccallback_t acg_callback;
+ adccallback_t acg_endcb;
/* End of the mandatory fields.*/
/**
* @brief ADC CR1 register initialization data.
@@ -219,10 +222,20 @@ struct ADCDriver { const ADCConversionGroup *ad_grpp;
#if ADC_USE_WAIT || defined(__DOXYGEN__)
/**
- * @brief Synchronization semaphore.
+ * @brief Waiting thread.
*/
- Semaphore ad_sem;
+ Thread *ad_thread;
#endif
+#if ADC_USE_MUTUAL_EXCLUSION || defined(__DOXYGEN__)
+#if CH_USE_MUTEXES || defined(__DOXYGEN__)
+ /**
+ * @brief Mutex protecting the peripheral.
+ */
+ Mutex ad_mutex;
+#elif CH_USE_SEMAPHORES
+ Semaphore ad_semaphore;
+#endif
+#endif /* ADC_USE_MUTUAL_EXCLUSION */
#if defined(ADC_DRIVER_EXT_FIELDS)
ADC_DRIVER_EXT_FIELDS
#endif
diff --git a/os/hal/platforms/STM32/spi_lld.c b/os/hal/platforms/STM32/spi_lld.c index 4dc18e80c..87dff24d9 100644 --- a/os/hal/platforms/STM32/spi_lld.c +++ b/os/hal/platforms/STM32/spi_lld.c @@ -90,19 +90,9 @@ static void serve_interrupt(SPIDriver *spip) { /* Stop everything.*/
dma_stop(spip);
- /* If a callback is defined then invokes it.*/
- if (spip->spd_config->spc_endcb)
- spip->spd_config->spc_endcb(spip);
-
- /* Wakeup the waiting thread if any, note that the following macro is
- empty if the SPI_USE_WAIT option is disabled.*/
- _spi_wakeup(spip);
-
- /* State change.*/
- if (spip->spd_state == SPI_SYNC)
- spip->spd_state = SPI_READY;
- else
- spip->spd_state = SPI_SELECTED;
+ /* Portable SPI ISR code defined in the high level driver, note, it is
+ a macro.*/
+ _spi_isr_code(spip);
}
/*===========================================================================*/
diff --git a/os/hal/platforms/STM32/spi_lld.h b/os/hal/platforms/STM32/spi_lld.h index fcca37c27..5da92d1f7 100644 --- a/os/hal/platforms/STM32/spi_lld.h +++ b/os/hal/platforms/STM32/spi_lld.h @@ -178,7 +178,10 @@ typedef void (*spicallback_t)(SPIDriver *spip); */
typedef struct {
/**
- * @brief Operation complete callback.
+ * @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.*/
@@ -204,6 +207,10 @@ 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.
@@ -220,10 +227,6 @@ struct SPIDriver{ Semaphore spd_semaphore;
#endif
#endif /* SPI_USE_MUTUAL_EXCLUSION */
- /**
- * @brief Current configuration data.
- */
- const SPIConfig *spd_config;
#if defined(SPI_DRIVER_EXT_FIELDS)
SPI_DRIVER_EXT_FIELDS
#endif
diff --git a/os/hal/src/adc.c b/os/hal/src/adc.c index 1d407d927..0d33cde4e 100644 --- a/os/hal/src/adc.c +++ b/os/hal/src/adc.c @@ -71,7 +71,17 @@ void adcObjectInit(ADCDriver *adcp) { adcp->ad_depth = 0;
adcp->ad_grpp = NULL;
#if ADC_USE_WAIT
- chSemInit(&adcp->ad_sem, 0);
+ adcp->ad_thread = NULL;
+#endif /* ADC_USE_WAIT */
+#if ADC_USE_MUTUAL_EXCLUSION
+#if CH_USE_MUTEXES
+ chMtxInit(&adcp->ad_mutex);
+#else
+ chSemInit(&adcp->ad_semaphore, 1);
+#endif
+#endif /* ADC_USE_MUTUAL_EXCLUSION */
+#if defined(ADC_DRIVER_EXT_INIT_HOOK)
+ ADC_DRIVER_EXT_INIT_HOOK(adcp);
#endif
}
@@ -89,8 +99,7 @@ void adcStart(ADCDriver *adcp, const ADCConfig *config) { chSysLock();
chDbgAssert((adcp->ad_state == ADC_STOP) || (adcp->ad_state == ADC_READY),
- "adcStart(), #1",
- "invalid state");
+ "adcStart(), #1", "invalid state");
adcp->ad_config = config;
adc_lld_start(adcp);
adcp->ad_state = ADC_READY;
@@ -110,8 +119,7 @@ void adcStop(ADCDriver *adcp) { chSysLock();
chDbgAssert((adcp->ad_state == ADC_STOP) || (adcp->ad_state == ADC_READY),
- "adcStop(), #1",
- "invalid state");
+ "adcStop(), #1", "invalid state");
adc_lld_stop(adcp);
adcp->ad_state = ADC_STOP;
chSysUnlock();
@@ -119,18 +127,7 @@ void adcStop(ADCDriver *adcp) { /**
* @brief Starts an ADC conversion.
- * @details Starts a conversion operation, there are two kind of conversion
- * modes:
- * - <b>LINEAR</b>, in this mode the buffer is filled once and then
- * the conversion stops automatically.
- * - <b>CIRCULAR</b>, in this mode the conversion never stops and
- * the buffer is filled circularly.<br>
- * During the conversion the callback function is invoked when
- * the buffer is 50% filled and when the buffer is 100% filled,
- * this way is possible to process the conversion stream in real
- * time. This kind of conversion can only be stopped by explicitly
- * invoking @p adcStopConversion().
- * .
+ * @details Starts an asynchronous conversion operation.
* @note The buffer is organized as a matrix of M*N elements where M is the
* channels number configured into the conversion group and N is the
* buffer depth. The samples are sequentially written into the buffer
@@ -141,38 +138,22 @@ void adcStop(ADCDriver *adcp) { * @param[out] samples pointer to the samples buffer
* @param[in] depth buffer depth (matrix rows number). The buffer depth
* must be one or an even number.
- * @return The operation status.
- * @retval FALSE the conversion has been started.
- * @retval TRUE the driver is busy, conversion not started.
*
* @api
*/
-bool_t adcStartConversion(ADCDriver *adcp,
- const ADCConversionGroup *grpp,
- adcsample_t *samples,
- size_t depth) {
- bool_t result;
+void adcStartConversion(ADCDriver *adcp,
+ const ADCConversionGroup *grpp,
+ adcsample_t *samples,
+ size_t depth) {
chSysLock();
- result = adcStartConversionI(adcp, grpp, samples, depth);
+ adcStartConversionI(adcp, grpp, samples, depth);
chSysUnlock();
- return result;
}
/**
* @brief Starts an ADC conversion.
- * @details Starts a conversion operation, there are two kind of conversion
- * modes:
- * - <b>LINEAR</b>, in this mode the buffer is filled once and then
- * the conversion stops automatically.
- * - <b>CIRCULAR</b>, in this mode the conversion never stops and
- * the buffer is filled circularly.<br>
- * During the conversion the callback function is invoked when
- * the buffer is 50% filled and when the buffer is 100% filled,
- * this way is possible to process the conversion stream in real
- * time. This kind of conversion can only be stopped by explicitly
- * invoking @p adcStopConversion().
- * .
+ * @details Starts an asynchronous conversion operation.
* @note The buffer is organized as a matrix of M*N elements where M is the
* channels number configured into the conversion group and N is the
* buffer depth. The samples are sequentially written into the buffer
@@ -183,34 +164,25 @@ bool_t adcStartConversion(ADCDriver *adcp, * @param[out] samples pointer to the samples buffer
* @param[in] depth buffer depth (matrix rows number). The buffer depth
* must be one or an even number.
- * @return The operation status.
- * @retval FALSE the conversion has been started.
- * @retval TRUE the driver is busy, conversion not started.
*
* @iclass
*/
-bool_t adcStartConversionI(ADCDriver *adcp,
- const ADCConversionGroup *grpp,
- adcsample_t *samples,
- size_t depth) {
+void adcStartConversionI(ADCDriver *adcp,
+ const ADCConversionGroup *grpp,
+ adcsample_t *samples,
+ size_t depth) {
chDbgCheck((adcp != NULL) && (grpp != NULL) && (samples != NULL) &&
((depth == 1) || ((depth & 1) == 0)),
"adcStartConversionI");
- chDbgAssert((adcp->ad_state == ADC_READY) ||
- (adcp->ad_state == ADC_RUNNING) ||
- (adcp->ad_state == ADC_COMPLETE),
- "adcStartConversionI(), #1",
- "invalid state");
- if (adcp->ad_state == ADC_RUNNING)
- return TRUE;
+ chDbgAssert(adcp->ad_state == ADC_READY,
+ "adcStartConversionI(), #1", "not ready");
adcp->ad_samples = samples;
adcp->ad_depth = depth;
adcp->ad_grpp = grpp;
+ adcp->ad_state = ADC_ACTIVE;
adc_lld_start_conversion(adcp);
- adcp->ad_state = ADC_RUNNING;
- return FALSE;
}
/**
@@ -229,21 +201,15 @@ void adcStopConversion(ADCDriver *adcp) { chSysLock();
chDbgAssert((adcp->ad_state == ADC_READY) ||
- (adcp->ad_state == ADC_RUNNING) ||
+ (adcp->ad_state == ADC_ACTIVE) ||
(adcp->ad_state == ADC_COMPLETE),
- "adcStopConversion(), #1",
- "invalid state");
- if (adcp->ad_state == ADC_RUNNING) {
+ "adcStopConversion(), #1", "invalid state");
+ if (adcp->ad_state != ADC_READY) {
adc_lld_stop_conversion(adcp);
adcp->ad_grpp = NULL;
adcp->ad_state = ADC_READY;
-#if ADC_USE_WAIT
- chSemResetI(&adcp->ad_sem, 0);
- chSchRescheduleS();
-#endif
+ _adc_reset_s(adcp);
}
- else
- adcp->ad_state = ADC_READY;
chSysUnlock();
}
@@ -262,61 +228,102 @@ void adcStopConversionI(ADCDriver *adcp) { chDbgCheck(adcp != NULL, "adcStopConversionI");
chDbgAssert((adcp->ad_state == ADC_READY) ||
- (adcp->ad_state == ADC_RUNNING) ||
+ (adcp->ad_state == ADC_ACTIVE) ||
(adcp->ad_state == ADC_COMPLETE),
- "adcStopConversionI(), #1",
- "invalid state");
- if (adcp->ad_state == ADC_RUNNING) {
+ "adcStopConversionI(), #1", "invalid state");
+ if (adcp->ad_state != ADC_READY) {
adc_lld_stop_conversion(adcp);
adcp->ad_grpp = NULL;
adcp->ad_state = ADC_READY;
-#if ADC_USE_WAIT
- chSemResetI(&adcp->ad_sem, 0);
-#endif
+ _adc_reset_i(adcp);
}
- else
- adcp->ad_state = ADC_READY;
}
#if ADC_USE_WAIT || defined(__DOXYGEN__)
/**
- * @brief Waits for completion.
- * @details If the conversion is not completed or not yet started then the
- * invoking thread waits for a conversion completion event.
- * @pre In order to use this function the option @p ADC_USE_WAIT must be
- * enabled.
+ * @brief Performs an ADC conversion.
+ * @details Performs a synchronous conversion operation.
+ * @note The buffer is organized as a matrix of M*N elements where M is the
+ * channels number configured into the conversion group and N is the
+ * buffer depth. The samples are sequentially written into the buffer
+ * with no gaps.
*
* @param[in] adcp pointer to the @p ADCDriver object
- * @param[in] timeout the number of ticks before the operation timeouts,
- * the following special values are allowed:
- * - @a TIME_IMMEDIATE immediate timeout.
- * - @a TIME_INFINITE no timeout.
- * .
+ * @param[in] grpp pointer to a @p ADCConversionGroup object
+ * @param[out] samples pointer to the samples buffer
+ * @param[in] depth buffer depth (matrix rows number). The buffer depth
+ * must be one or an even number.
* @return The operation result.
- * @retval RDY_OK conversion finished.
- * @retval RDY_TIMEOUT conversion not finished within the specified time.
+ * @retval RDY_OK Conversion finished.
+ * @retval RDY_RESET The conversion has been stopped using
+ * @p acdStopConversion() or @p acdStopConversionI(),
+ * the result buffer may contain incorrect data.
*
- * @init
+ * @api
*/
-msg_t adcWaitConversion(ADCDriver *adcp, systime_t timeout) {
+msg_t adcConvert(ADCDriver *adcp,
+ const ADCConversionGroup *grpp,
+ adcsample_t *samples,
+ size_t depth) {
+ msg_t msg;
chSysLock();
- chDbgAssert((adcp->ad_state == ADC_READY) ||
- (adcp->ad_state == ADC_RUNNING) ||
- (adcp->ad_state == ADC_COMPLETE),
- "adcWaitConversion(), #1",
- "invalid state");
- if (adcp->ad_state != ADC_COMPLETE) {
- if (chSemWaitTimeoutS(&adcp->ad_sem, timeout) == RDY_TIMEOUT) {
- chSysUnlock();
- return RDY_TIMEOUT;
- }
- }
+ chDbgAssert(adcp->ad_config->ac_endcb == NULL,
+ "adcConvert(), #1", "has callback");
+ adcStartConversionI(adcp, grpp, samples, depth);
+ (adcp)->ad_thread = chThdSelf();
+ chSchGoSleepS(THD_STATE_SUSPENDED);
+ msg = chThdSelf()->p_u.rdymsg;
chSysUnlock();
- return RDY_OK;
+ return msg;
}
#endif /* ADC_USE_WAIT */
+#if ADC_USE_MUTUAL_EXCLUSION || defined(__DOXYGEN__)
+/**
+ * @brief Gains exclusive access to the ADC peripheral.
+ * @details This function tries to gain ownership to the ADC bus, if the bus
+ * is already being used then the invoking thread is queued.
+ * @pre In order to use this function the option @p ADC_USE_MUTUAL_EXCLUSION
+ * must be enabled.
+ *
+ * @param[in] adcp pointer to the @p ADCDriver object
+ *
+ * @api
+ */
+void adcAcquireBus(ADCDriver *adcp) {
+
+ chDbgCheck(adcp != NULL, "adcAcquireBus");
+
+#if CH_USE_MUTEXES
+ chMtxLock(&adcp->ad_mutex);
+#elif CH_USE_SEMAPHORES
+ chSemWait(&adcp->ad_semaphore);
+#endif
+}
+
+/**
+ * @brief Releases exclusive access to the ADC peripheral.
+ * @pre In order to use this function the option @p ADC_USE_MUTUAL_EXCLUSION
+ * must be enabled.
+ *
+ * @param[in] adcp pointer to the @p ADCDriver object
+ *
+ * @api
+ */
+void adcReleaseBus(ADCDriver *adcp) {
+
+ chDbgCheck(adcp != NULL, "adcReleaseBus");
+
+#if CH_USE_MUTEXES
+ (void)adcp;
+ chMtxUnlock();
+#elif CH_USE_SEMAPHORES
+ chSemSignal(&adcp->ad_semaphore);
+#endif
+}
+#endif /* ADC_USE_MUTUAL_EXCLUSION */
+
#endif /* CH_HAL_USE_ADC */
/** @} */
diff --git a/os/hal/src/mmc_spi.c b/os/hal/src/mmc_spi.c index 76b710a03..49f75c3cc 100644 --- a/os/hal/src/mmc_spi.c +++ b/os/hal/src/mmc_spi.c @@ -84,13 +84,13 @@ static void wait(MMCDriver *mmcp) { uint8_t buf[4];
for (i = 0; i < 16; i++) {
- spiReceiveWait(mmcp->mmc_spip, 1, buf);
+ spiReceive(mmcp->mmc_spip, 1, buf);
if (buf[0] == 0xFF)
break;
}
/* Looks like it is a long wait.*/
while (TRUE) {
- spiReceiveWait(mmcp->mmc_spip, 1, buf);
+ spiReceive(mmcp->mmc_spip, 1, buf);
if (buf[0] == 0xFF)
break;
#ifdef MMC_NICE_WAITING
@@ -121,7 +121,7 @@ static void send_hdr(MMCDriver *mmcp, uint8_t cmd, uint32_t arg) { buf[3] = arg >> 8;
buf[4] = arg;
buf[5] = 0x95; /* Valid for CMD0 ignored by other commands. */
- spiSendWait(mmcp->mmc_spip, 6, buf);
+ spiSend(mmcp->mmc_spip, 6, buf);
}
/**
@@ -138,7 +138,7 @@ static uint8_t recvr1(MMCDriver *mmcp) { uint8_t r1[1];
for (i = 0; i < 9; i++) {
- spiReceiveWait(mmcp->mmc_spip, 1, r1);
+ spiReceive(mmcp->mmc_spip, 1, r1);
if (r1[0] != 0xFF)
return r1[0];
}
@@ -178,7 +178,7 @@ static void sync(MMCDriver *mmcp) { spiSelect(mmcp->mmc_spip);
while (TRUE) {
- spiReceiveWait(mmcp->mmc_spip, 1, buf);
+ spiReceive(mmcp->mmc_spip, 1, buf);
if (buf[0] == 0xFF)
break;
#ifdef MMC_NICE_WAITING
@@ -306,7 +306,7 @@ bool_t mmcConnect(MMCDriver *mmcp) { if (mmcp->mmc_state == MMC_INSERTED) {
/* Slow clock mode and 128 clock pulses.*/
spiStart(mmcp->mmc_spip, mmcp->mmc_lscfg);
- spiSynchronizeWait(mmcp->mmc_spip, 16);
+ spiIgnore(mmcp->mmc_spip, 16);
/* SPI mode selection.*/
i = 0;
@@ -453,11 +453,11 @@ bool_t mmcSequentialRead(MMCDriver *mmcp, uint8_t *buffer) { chSysUnlock();
for (i = 0; i < MMC_WAIT_DATA; i++) {
- spiReceiveWait(mmcp->mmc_spip, 1, buffer);
+ spiReceive(mmcp->mmc_spip, 1, buffer);
if (buffer[0] == 0xFE) {
- spiReceiveWait(mmcp->mmc_spip, MMC_SECTOR_SIZE, buffer);
+ spiReceive(mmcp->mmc_spip, MMC_SECTOR_SIZE, buffer);
/* CRC ignored. */
- spiIgnoreWait(mmcp->mmc_spip, 2);
+ spiIgnore(mmcp->mmc_spip, 2);
return FALSE;
}
}
@@ -493,7 +493,7 @@ bool_t mmcStopSequentialRead(MMCDriver *mmcp) { }
chSysUnlock();
- spiSendWait(mmcp->mmc_spip, sizeof(stopcmd), stopcmd);
+ spiSend(mmcp->mmc_spip, sizeof(stopcmd), stopcmd);
/* result = recvr1(mmcp) != 0x00;*/
/* Note, ignored r1 response, it can be not zero, unknown issue.*/
recvr1(mmcp);
@@ -568,10 +568,10 @@ bool_t mmcSequentialWrite(MMCDriver *mmcp, const uint8_t *buffer) { }
chSysUnlock();
- spiSendWait(mmcp->mmc_spip, sizeof(start), start); /* Data prologue. */
- spiSendWait(mmcp->mmc_spip, MMC_SECTOR_SIZE, buffer); /* Data. */
- spiIgnoreWait(mmcp->mmc_spip, 2); /* CRC ignored. */
- spiReceiveWait(mmcp->mmc_spip, 1, b);
+ spiSend(mmcp->mmc_spip, sizeof(start), start); /* Data prologue. */
+ spiSend(mmcp->mmc_spip, MMC_SECTOR_SIZE, buffer); /* Data. */
+ spiIgnore(mmcp->mmc_spip, 2); /* CRC ignored. */
+ spiReceive(mmcp->mmc_spip, 1, b);
if ((b[0] & 0x1F) == 0x05) {
wait(mmcp);
return FALSE;
@@ -608,7 +608,7 @@ bool_t mmcStopSequentialWrite(MMCDriver *mmcp) { }
chSysUnlock();
- spiSendWait(mmcp->mmc_spip, sizeof(stop), stop);
+ spiSend(mmcp->mmc_spip, sizeof(stop), stop);
spiUnselect(mmcp->mmc_spip);
chSysLock();
diff --git a/os/hal/src/spi.c b/os/hal/src/spi.c index 414eb61db..fe7b729bd 100644 --- a/os/hal/src/spi.c +++ b/os/hal/src/spi.c @@ -66,6 +66,7 @@ void spiInit(void) { void spiObjectInit(SPIDriver *spip) {
spip->spd_state = SPI_STOP;
+ spip->spd_config = NULL;
#if SPI_USE_WAIT
spip->spd_thread = NULL;
#endif /* SPI_USE_WAIT */
@@ -76,8 +77,6 @@ void spiObjectInit(SPIDriver *spip) { chSemInit(&spip->spd_semaphore, 1);
#endif
#endif /* SPI_USE_MUTUAL_EXCLUSION */
- spip->spd_config = NULL;
- /* Optional, user-defined initializer.*/
#if defined(SPI_DRIVER_EXT_INIT_HOOK)
SPI_DRIVER_EXT_INIT_HOOK(spip);
#endif
@@ -97,8 +96,7 @@ void spiStart(SPIDriver *spip, const SPIConfig *config) { chSysLock();
chDbgAssert((spip->spd_state == SPI_STOP) || (spip->spd_state == SPI_READY),
- "spiStart(), #1",
- "invalid state");
+ "spiStart(), #1", "invalid state");
spip->spd_config = config;
spi_lld_start(spip);
spip->spd_state = SPI_READY;
@@ -118,8 +116,7 @@ void spiStop(SPIDriver *spip) { chSysLock();
chDbgAssert((spip->spd_state == SPI_STOP) || (spip->spd_state == SPI_READY),
- "spiStop(), #1",
- "invalid state");
+ "spiStop(), #1", "invalid state");
spi_lld_stop(spip);
spip->spd_state = SPI_STOP;
chSysUnlock();
@@ -137,10 +134,8 @@ void spiSelect(SPIDriver *spip) { chDbgCheck(spip != NULL, "spiSelect");
chSysLock();
- chDbgAssert((spip->spd_state == SPI_READY) ||
- (spip->spd_state == SPI_SELECTED),
- "spiSelect(), #1",
- "not idle");
+ chDbgAssert(spip->spd_state == SPI_READY,
+ "spiSelect(), #1", "not ready");
spiSelectI(spip);
chSysUnlock();
}
@@ -158,39 +153,9 @@ void spiUnselect(SPIDriver *spip) { chDbgCheck(spip != NULL, "spiUnselect");
chSysLock();
- chDbgAssert((spip->spd_state == SPI_READY) ||
- (spip->spd_state == SPI_SELECTED),
- "spiUnselect(), #1",
- "not locked");
- spiUnselectI(spip);
- chSysUnlock();
-}
-
-/**
- * @brief Emits a train of clock pulses on the SPI bus.
- * @details This asynchronous function starts the emission of a train of
- * clock pulses without asserting any slave.
- * @note This functionality is not usually required by the SPI protocol
- * but it is required by initialization procedure of MMC/SD cards
- * in SPI mode.
- * @post At the end of the operation the configured callback is invoked.
- *
- * @param[in] spip pointer to the @p SPIDriver object
- * @param[in] n number of words to be clocked. The number of pulses
- * is equal to the number of words multiplied to the
- * configured word size in bits.
- *
- * @api
- */
-void spiSynchronize(SPIDriver *spip, size_t n) {
-
- chDbgCheck((spip != NULL) && (n > 0), "spiSynchronize");
-
- chSysLock();
chDbgAssert(spip->spd_state == SPI_READY,
- "spiSynchronize(), #1",
- "not ready");
- spiSynchronizeI(spip, n);
+ "spiUnselect(), #1", "not ready");
+ spiUnselectI(spip);
chSysUnlock();
}
@@ -207,15 +172,14 @@ void spiSynchronize(SPIDriver *spip, size_t n) { *
* @api
*/
-void spiIgnore(SPIDriver *spip, size_t n) {
+void spiStartIgnore(SPIDriver *spip, size_t n) {
- chDbgCheck((spip != NULL) && (n > 0), "spiIgnore");
+ chDbgCheck((spip != NULL) && (n > 0), "spiStartIgnore");
chSysLock();
- chDbgAssert(spip->spd_state == SPI_SELECTED,
- "spiIgnore(), #1",
- "not selected");
- spiIgnoreI(spip, n);
+ chDbgAssert(spip->spd_state == SPI_READY,
+ "spiStartIgnore(), #1", "not ready");
+ spiStartIgnoreI(spip, n);
chSysUnlock();
}
@@ -236,16 +200,16 @@ void spiIgnore(SPIDriver *spip, size_t n) { *
* @api
*/
-void spiExchange(SPIDriver *spip, size_t n, const void *txbuf, void *rxbuf) {
+void spiStartExchange(SPIDriver *spip, size_t n,
+ const void *txbuf, void *rxbuf) {
chDbgCheck((spip != NULL) && (n > 0) && (rxbuf != NULL) && (txbuf != NULL),
- "spiExchange");
+ "spiStartExchange");
chSysLock();
- chDbgAssert(spip->spd_state == SPI_SELECTED,
- "spiExchange(), #1",
- "not selected");
- spiExchangeI(spip, n, txbuf, rxbuf);
+ chDbgAssert(spip->spd_state == SPI_READY,
+ "spiStartExchange(), #1", "not ready");
+ spiStartExchangeI(spip, n, txbuf, rxbuf);
chSysUnlock();
}
@@ -264,16 +228,15 @@ void spiExchange(SPIDriver *spip, size_t n, const void *txbuf, void *rxbuf) { *
* @api
*/
-void spiSend(SPIDriver *spip, size_t n, const void *txbuf) {
+void spiStartSend(SPIDriver *spip, size_t n, const void *txbuf) {
chDbgCheck((spip != NULL) && (n > 0) && (txbuf != NULL),
- "spiSend");
+ "spiStartSend");
chSysLock();
- chDbgAssert(spip->spd_state == SPI_SELECTED,
- "spiSend(), #1",
- "not selected");
- spiSendI(spip, n, txbuf);
+ chDbgAssert(spip->spd_state == SPI_READY,
+ "spiStartSend(), #1", "not ready");
+ spiStartSendI(spip, n, txbuf);
chSysUnlock();
}
@@ -292,107 +255,44 @@ void spiSend(SPIDriver *spip, size_t n, const void *txbuf) { *
* @api
*/
-void spiReceive(SPIDriver *spip, size_t n, void *rxbuf) {
+void spiStartReceive(SPIDriver *spip, size_t n, void *rxbuf) {
chDbgCheck((spip != NULL) && (n > 0) && (rxbuf != NULL),
- "spiReceive");
-
- chSysLock();
- chDbgAssert(spip->spd_state == SPI_SELECTED,
- "spiReceive(), #1",
- "not selected");
- spiReceiveI(spip, n, rxbuf);
- chSysUnlock();
-}
-
-#if SPI_USE_WAIT || defined(__DOXYGEN__)
-/**
- * @brief Waits 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.
- * @pre In order to use this function the option @p SPI_USE_WAIT must be
- * enabled.
- * @post On exit the SPI driver is ready to accept more commands.
- * @note No more than one thread can wait on a SPI driver using
- * this function.
- *
- * @param[in] spip pointer to the @p SPIDriver object
- *
- * @api
- */
-void spiWait(SPIDriver *spip) {
-
- 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),
- "spiWait(), #1",
- "invalid state");
- if ((spip->spd_state == SPI_ACTIVE) || (spip->spd_state == SPI_SYNC))
- spiWaitS(spip);
- chSysUnlock();
-}
-
-/**
- * @brief Emits a train of clock pulses on the SPI bus.
- * @details This synchronous function performs the emission of a train of
- * clock pulses without asserting any slave.
- * @pre In order to use this function the option @p SPI_USE_WAIT must be
- * enabled.
- * @post At the end of the operation the configured callback is invoked.
- * @note This functionality is not usually required by the SPI protocol
- * but it is required by initialization procedure of MMC/SD cards
- * in SPI mode.
- *
- * @param[in] spip pointer to the @p SPIDriver object
- * @param[in] n number of words to be clocked. The number of pulses
- * is equal to the number of words multiplied to the
- * configured word size in bits.
- *
- * @api
- */
-void spiSynchronizeWait(SPIDriver *spip, size_t n) {
-
- chDbgCheck((spip != NULL) && (n > 0), "spiSynchronizeWait");
+ "spiStartReceive");
chSysLock();
chDbgAssert(spip->spd_state == SPI_READY,
- "spiSynchronizeWait(), #1",
- "not ready");
- spiSynchronizeI(spip, n);
- spiWaitS(spip);
+ "spiStartReceive(), #1", "not ready");
+ spiStartReceiveI(spip, n, rxbuf);
chSysUnlock();
}
+#if SPI_USE_WAIT || defined(__DOXYGEN__)
/**
* @brief Ignores data on the SPI bus.
* @details This synchronous function performs the transmission of a series of
* idle words on the SPI bus and ignores the received data.
- * @pre A slave must have been selected using @p spiSelect() or
- * @p spiSelectI().
* @pre In order to use this function the option @p SPI_USE_WAIT must be
* enabled.
- * @post At the end of the operation the configured callback is invoked.
+ * @pre In order to use this function the driver must have been configured
+ * without callbacks (@p spc_endcb = @p NULL).
*
* @param[in] spip pointer to the @p SPIDriver object
* @param[in] n number of words to be ignored
*
* @api
*/
-void spiIgnoreWait(SPIDriver *spip, size_t n) {
+void spiIgnore(SPIDriver *spip, size_t n) {
chDbgCheck((spip != NULL) && (n > 0), "spiIgnoreWait");
chSysLock();
- chDbgAssert(spip->spd_state == SPI_SELECTED,
- "spiIgnoreWait(), #1",
- "not selected");
- spiIgnoreI(spip, n);
- spiWaitS(spip);
+ chDbgAssert(spip->spd_state == SPI_READY,
+ "spiIgnore(), #1", "not ready");
+ chDbgAssert(spip->spd_config->spc_endcb == NULL,
+ "spiIgnore(), #2", "has callback");
+ spiStartIgnoreI(spip, n);
+ _spi_wait(spip);
chSysUnlock();
}
@@ -400,11 +300,10 @@ void spiIgnoreWait(SPIDriver *spip, size_t n) { * @brief Exchanges data on the SPI bus.
* @details This synchronous function performs a simultaneous transmit/receive
* operation.
- * @pre A slave must have been selected using @p spiSelect() or
- * @p spiSelectI().
* @pre In order to use this function the option @p SPI_USE_WAIT must be
* enabled.
- * @post At the end of the operation the configured callback is invoked.
+ * @pre In order to use this function the driver must have been configured
+ * without callbacks (@p spc_endcb = @p NULL).
* @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.
*
@@ -415,29 +314,29 @@ void spiIgnoreWait(SPIDriver *spip, size_t n) { *
* @api
*/
-void spiExchangeWait(SPIDriver *spip, size_t n,
+void spiExchange(SPIDriver *spip, size_t n,
const void *txbuf, void *rxbuf) {
chDbgCheck((spip != NULL) && (n > 0) && (rxbuf != NULL) && (txbuf != NULL),
- "spiExchangeWait");
+ "spiExchange");
chSysLock();
- chDbgAssert(spip->spd_state == SPI_SELECTED,
- "spiExchangeWait(), #1",
- "not selected");
- spiExchangeI(spip, n, txbuf, rxbuf);
- spiWaitS(spip);
+ chDbgAssert(spip->spd_state == SPI_READY,
+ "spiExchange(), #1", "not ready");
+ chDbgAssert(spip->spd_config->spc_endcb == NULL,
+ "spiExchange(), #2", "has callback");
+ spiStartExchangeI(spip, n, txbuf, rxbuf);
+ _spi_wait(spip);
chSysUnlock();
}
/**
* @brief Sends data over the SPI bus.
* @details This synchronous function performs a transmit operation.
- * @pre A slave must have been selected using @p spiSelect() or
- * @p spiSelectI().
* @pre In order to use this function the option @p SPI_USE_WAIT must be
* enabled.
- * @post At the end of the operation the configured callback is invoked.
+ * @pre In order to use this function the driver must have been configured
+ * without callbacks (@p spc_endcb = @p NULL).
* @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.
*
@@ -447,28 +346,28 @@ void spiExchangeWait(SPIDriver *spip, size_t n, *
* @api
*/
-void spiSendWait(SPIDriver *spip, size_t n, const void *txbuf) {
+void spiSend(SPIDriver *spip, size_t n, const void *txbuf) {
chDbgCheck((spip != NULL) && (n > 0) && (txbuf != NULL),
- "spiSendWait");
+ "spiSend");
chSysLock();
- chDbgAssert(spip->spd_state == SPI_SELECTED,
- "spiSendWait(), #1",
- "not selected");
- spiSendI(spip, n, txbuf);
- spiWaitS(spip);
+ chDbgAssert(spip->spd_state == SPI_READY,
+ "spiSend(), #1", "not ready");
+ chDbgAssert(spip->spd_config->spc_endcb == NULL,
+ "spiSend(), #2", "has callback");
+ spiStartSendI(spip, n, txbuf);
+ _spi_wait(spip);
chSysUnlock();
}
/**
* @brief Receives data from the SPI bus.
* @details This synchronous function performs a receive operation.
- * @pre A slave must have been selected using @p spiSelect() or
- * @p spiSelectI().
* @pre In order to use this function the option @p SPI_USE_WAIT must be
* enabled.
- * @post At the end of the operation the configured callback is invoked.
+ * @pre In order to use this function the driver must have been configured
+ * without callbacks (@p spc_endcb = @p NULL).
* @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.
*
@@ -478,17 +377,18 @@ void spiSendWait(SPIDriver *spip, size_t n, const void *txbuf) { *
* @api
*/
-void spiReceiveWait(SPIDriver *spip, size_t n, void *rxbuf) {
+void spiReceive(SPIDriver *spip, size_t n, void *rxbuf) {
chDbgCheck((spip != NULL) && (n > 0) && (rxbuf != NULL),
- "spiReceiveWait");
+ "spiReceive");
chSysLock();
- chDbgAssert(spip->spd_state == SPI_SELECTED,
- "spiReceiveWait(), #1",
- "not selected");
- spiReceiveI(spip, n, rxbuf);
- spiWaitS(spip);
+ chDbgAssert(spip->spd_state == SPI_READY,
+ "spiReceive(), #1", "not ready");
+ chDbgAssert(spip->spd_config->spc_endcb == NULL,
+ "spiReceive(), #2", "has callback");
+ spiStartReceiveI(spip, n, rxbuf);
+ _spi_wait(spip);
chSysUnlock();
}
#endif /* SPI_USE_WAIT */
diff --git a/os/hal/templates/adc_lld.h b/os/hal/templates/adc_lld.h index 2b2e8dd58..9f436ffbc 100644 --- a/os/hal/templates/adc_lld.h +++ b/os/hal/templates/adc_lld.h @@ -93,8 +93,11 @@ typedef struct { adc_channels_num_t acg_num_channels;
/**
* @brief Callback function associated to the group 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.
*/
- adccallback_t acg_callback;
+ adccallback_t acg_endcb;
/* End of the mandatory fields.*/
} ADCConversionGroup;
@@ -136,10 +139,20 @@ struct ADCDriver { const ADCConversionGroup *ad_grpp;
#if ADC_USE_WAIT || defined(__DOXYGEN__)
/**
- * @brief Synchronization semaphore.
+ * @brief Waiting thread.
*/
- Semaphore ad_sem;
+ Thread *ad_thread;
+#endif /* SPI_USE_WAIT */
+#if ADC_USE_MUTUAL_EXCLUSION || defined(__DOXYGEN__)
+#if CH_USE_MUTEXES || defined(__DOXYGEN__)
+ /**
+ * @brief Mutex protecting the peripheral.
+ */
+ Mutex ad_mutex;
+#elif CH_USE_SEMAPHORES
+ Semaphore ad_semaphore;
#endif
+#endif /* ADC_USE_MUTUAL_EXCLUSION */
#if defined(ADC_DRIVER_EXT_FIELDS)
ADC_DRIVER_EXT_FIELDS
#endif
diff --git a/os/hal/templates/spi_lld.h b/os/hal/templates/spi_lld.h index 582b56678..a9aeca56f 100644 --- a/os/hal/templates/spi_lld.h +++ b/os/hal/templates/spi_lld.h @@ -67,6 +67,9 @@ typedef void (*spicallback_t)(SPIDriver *spip); typedef struct {
/**
* @brief Operation complete callback. + * @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.*/
@@ -82,6 +85,10 @@ 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. @@ -98,10 +105,6 @@ struct SPIDriver { Semaphore spd_semaphore;
#endif
#endif /* SPI_USE_MUTUAL_EXCLUSION */
- /**
- * @brief Current configuration data.
- */
- const SPIConfig *spd_config;
#if defined(SPI_DRIVER_EXT_FIELDS)
SPI_DRIVER_EXT_FIELDS
#endif
diff --git a/readme.txt b/readme.txt index 26ac0e130..a0fbd9688 100644 --- a/readme.txt +++ b/readme.txt @@ -95,19 +95,15 @@ adcStartConversion() (bug 3039890)(backported to 2.0.3).
- NEW: New I2C driver model (not complete and no implementations yet).
- NEW: New SPI driver model, the new model supports both synchronous and
- asynchronous APIs and, in general, simplifies the implementation of the
- low level driver. The API changed so be careful, for each old API there
- is not a signature-equivalent one with a different name, as example the
- old spiSend() now is named spiSendWait() because it is part of the
- synchronous set.
+ asynchronous operations and, in general, simplifies the implementation of the
+ low level driver. The state diagram changed slightly changed so be careful.
+- NEW: New ADC driver model, the new model supports both synchronous and
+ asynchronous operations and, in general, simplifies the implementation of the
+ low level driver. The state diagram changed slightly changed so be careful.
- NEW: Added pwmEnableChannelI() and pwmDisableChannelI() APIs to the PWM
driver in order to allow channel reprogramming from within callbacks or
interrupt handlers. The new APIs are implemented as macros so there is
no footprint overhead.
-- NEW: Added adcStartConversionI() and adcStopConversionI() APIs to the ADC
- driver in order to allow the driver control from within callbacks or
- interrupt handlers. Made the adcWaitConversion() API optional, this allows
- to save some space in Flash/RAM if it is not required.
- NEW: Added driver fields and initialization hooks for the callback-based
drivers. The hooks are named XXX_DRIVER_EXT_FIELDS and
XXX_DRIVER_EXT_INIT_HOOK().
@@ -146,9 +142,6 @@ - CHANGE: The event APIs chEvtPend() and chEvtClear() have been renamed
to chEvtAddFlags() and chEvtClearFlags() for consistency and correct
English. Changed the macro chEvtIsListening() in chEvtIsListeningI().
-- CHANGE: Added a parameter to the ADC driver callbacks, the pointer to the
- driver itself. Now the callback is statically associated to the conversion
- group, thanks to this the ADC function calls have one less parameter.
- CHANGE: Added a parameter to the PWM driver callbacks, the pointer to the
driver itself.
- CHANGE: Added a parameter to the UART driver callbacks, the pointer to the
diff --git a/testhal/STM32/SPI/main.c b/testhal/STM32/SPI/main.c index 09e3131f9..674a1c558 100644 --- a/testhal/STM32/SPI/main.c +++ b/testhal/STM32/SPI/main.c @@ -58,8 +58,8 @@ static msg_t spi_thread_1(void *p) { palClearPad(IOPORT3, GPIOC_LED); /* LED ON. */
spiStart(&SPID1, &hs_spicfg); /* Setup transfer parameters. */
spiSelect(&SPID1); /* Slave Select assertion. */
- spiExchangeWait(&SPID1, 512,
- txbuf, rxbuf); /* Atomic transfer operations. */
+ spiExchange(&SPID1, 512,
+ txbuf, rxbuf); /* Atomic transfer operations. */
spiUnselect(&SPID1); /* Slave Select de-assertion. */
spiReleaseBus(&SPID1); /* Ownership release. */
}
@@ -78,8 +78,8 @@ static msg_t spi_thread_2(void *p) { palSetPad(IOPORT3, GPIOC_LED); /* LED OFF. */
spiStart(&SPID1, &ls_spicfg); /* Setup transfer parameters. */
spiSelect(&SPID1); /* Slave Select assertion. */
- spiExchangeWait(&SPID1, 512,
- txbuf, rxbuf); /* Atomic transfer operations. */
+ spiExchange(&SPID1, 512,
+ txbuf, rxbuf); /* Atomic transfer operations. */
spiUnselect(&SPID1); /* Slave Select de-assertion. */
spiReleaseBus(&SPID1); /* Ownership release. */
}
|