git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@2250 35acf78f-673a-0410-8e92-d51de3d6d3f4
This commit is contained in:
parent
c505341086
commit
935e2fb27f
160
os/hal/hal.dox
160
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
|
||||
*/
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,34 +100,12 @@ 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
|
||||
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/*===========================================================================*/
|
||||
|
|
|
@ -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
|
||||
|
|
207
os/hal/src/adc.c
207
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 */
|
||||
|
||||
/** @} */
|
||||
|
|
|
@ -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();
|
||||
|
|
234
os/hal/src/spi.c
234
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();
|
||||
}
|
||||
|
@ -157,40 +152,10 @@ 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");
|
||||
"spiStartReceive");
|
||||
|
||||
chSysLock();
|
||||
chDbgAssert(spip->spd_state == SPI_SELECTED,
|
||||
"spiReceive(), #1",
|
||||
"not selected");
|
||||
spiReceiveI(spip, n, rxbuf);
|
||||
chDbgAssert(spip->spd_state == SPI_READY,
|
||||
"spiStartReceive(), #1", "not ready");
|
||||
spiStartReceiveI(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");
|
||||
|
||||
chSysLock();
|
||||
chDbgAssert(spip->spd_state == SPI_READY,
|
||||
"spiSynchronizeWait(), #1",
|
||||
"not ready");
|
||||
spiSynchronizeI(spip, n);
|
||||
spiWaitS(spip);
|
||||
chSysUnlock();
|
||||
}
|
||||
|
||||
/**
|
||||
* @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 */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
17
readme.txt
17
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
|
||||
|
|
|
@ -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. */
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue