diff options
Diffstat (limited to 'os')
| -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 | 
11 files changed, 464 insertions, 447 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
 | 
