git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@2246 35acf78f-673a-0410-8e92-d51de3d6d3f4

This commit is contained in:
gdisirio 2010-10-11 11:48:03 +00:00
parent 8cbeb405b9
commit 7c2a8e13d9
14 changed files with 499 additions and 166 deletions

View File

@ -39,7 +39,7 @@
/*===========================================================================*/
/**
* @brief Enables the @p spiWait() API.
* @brief Enables the "wait" APIs.
* @note Disabling this option saves both code and data space.
*/
#if !defined(SPI_USE_WAIT) || defined(__DOXYGEN__)
@ -112,9 +112,10 @@ typedef enum {
/**
* @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, while this is not
* usually required by the SPI protocol it is required by
* initialization procedure of MMC/SD cards in SPI mode.
* 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
@ -209,6 +210,51 @@ typedef enum {
spi_lld_receive(spip, n, rxbuf); \
}
#if SPI_USE_WAIT || defined(__DOXYGEN__)
/**
* @brief Awakens the thread waiting for operation completion, if any.
* @note This macro is meant to be used in the low level drivers
* implementation only.
*
* @param[in] spip pointer to the @p SPIDriver object
*
* @notapi
*/
#define _spi_wakeup(spip) { \
if ((spip)->spd_thread != NULL) { \
Thread *tp = (spip)->spd_thread; \
(spip)->spd_thread = NULL; \
tp->p_u.rdymsg = RDY_RESET; \
chSchReadyI(tp); \
} \
}
/**
* @brief Waits for operation completion.
* @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
*/
#define spiWaitS(spip) { \
chDbgAssert((spip)->spd_thread == NULL, \
"spiWaitS(), #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)
#endif /* !SPI_USE_WAIT */
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
@ -228,8 +274,12 @@ extern "C" {
void spiSend(SPIDriver *spip, size_t n, const void *txbuf);
void spiReceive(SPIDriver *spip, size_t n, void *rxbuf);
#if SPI_USE_WAIT
void _spi_wakeup(SPIDriver *spip, mag_t msg);
msg_t spiWait(SPIDriver *spip);
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);

View File

@ -57,30 +57,43 @@ SPIDriver SPID3;
/* Driver local functions. */
/*===========================================================================*/
static void spi_stop(SPIDriver *spip) {
/* Stops RX and TX DMA channels.*/
dmaChannelDisable(spip->spd_dmarx);
dmaChannelDisable(spip->spd_dmatx);
chSysLockFromIsr();
chSchReadyI(spip->spd_thread);
chSysUnlockFromIsr();
/**
* @brief Stops the SPI DMA channels.
*
* @param[in] spip pointer to the @p SPIDriver object
*/
#define dma_stop(spip) { \
dmaChannelDisable(spip->spd_dmatx); \
dmaChannelDisable(spip->spd_dmarx); \
}
static void spi_start_wait(SPIDriver *spip) {
/**
* @brief Starts the SPI DMA channels.
*
* @param[in] spip pointer to the @p SPIDriver object
*/
#define dma_start(spip) { \
dmaChannelEnable((spip)->spd_dmarx); \
dmaChannelEnable((spip)->spd_dmatx); \
}
chSysLock();
/**
* @brief Shared end-of-transfer service routine.
*
* @param[in] spip pointer to the @p SPIDriver object
*/
static void serve_interrupt(SPIDriver *spip) {
/* DMAs start.*/
dmaChannelEnable(spip->spd_dmarx);
dmaChannelEnable(spip->spd_dmatx);
/* Stops everything.*/
dma_stop(spip);
/* Wait for completion event.*/
spip->spd_thread = currp;
chSchGoSleepS(THD_STATE_SUSPENDED);
spip->spd_thread = NULL;
chSysUnlock();
/* 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);
}
/*===========================================================================*/
@ -97,10 +110,10 @@ CH_IRQ_HANDLER(DMA1_Ch2_IRQHandler) {
CH_IRQ_PROLOGUE();
spi_stop(&SPID1);
if ((STM32_DMA1->ISR & DMA_ISR_TEIF2) != 0) {
STM32_SPI_SPI1_DMA_ERROR_HOOK();
}
serve_interrupt(&SPID1);
dmaClearChannel(STM32_DMA1, STM32_DMA_CHANNEL_2);
CH_IRQ_EPILOGUE();
@ -132,10 +145,10 @@ CH_IRQ_HANDLER(DMA1_Ch4_IRQHandler) {
CH_IRQ_PROLOGUE();
spi_stop(&SPID2);
if ((STM32_DMA1->ISR & DMA_ISR_TEIF4) != 0) {
STM32_SPI_SPI2_DMA_ERROR_HOOK();
}
serve_interrupt(&SPID2);
dmaClearChannel(STM32_DMA1, STM32_DMA_CHANNEL_4);
CH_IRQ_EPILOGUE();
@ -167,10 +180,10 @@ CH_IRQ_HANDLER(DMA2_Ch1_IRQHandler) {
CH_IRQ_PROLOGUE();
spi_stop(&SPID3);
if ((STM32_DMA2->ISR & DMA_ISR_TEIF1) != 0) {
STM32_SPI_SPI3_DMA_ERROR_HOOK();
}
serve_interrupt(&SPID3);
dmaClearChannel(STM32_DMA2, STM32_DMA_CHANNEL_1);
CH_IRQ_EPILOGUE();
@ -365,9 +378,9 @@ void spi_lld_unselect(SPIDriver *spip) {
/**
* @brief Ignores data on the SPI bus.
* @details This function transmits a series of idle words on the SPI bus and
* ignores the received data. This function can be invoked even
* when a slave select signal has not been yet asserted.
* @details This asynchronous function starts the transmission of a series of
* idle words on the SPI bus and ignores the received data.
* @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 ignored
@ -382,14 +395,16 @@ void spi_lld_ignore(SPIDriver *spip, size_t n) {
spip->spd_dmaccr | DMA_CCR1_TCIE);
dmaChannelSetup(spip->spd_dmatx, n, &dummytx,
spip->spd_dmaccr | DMA_CCR1_DIR);
spi_start_wait(spip);
dma_start(spip);
}
/**
* @brief Exchanges data on the SPI bus.
* @details This function performs a simultaneous transmit/receive operation.
* @note The buffers are organized as uint8_t arrays for data sizes below or
* equal to 8 bits else it is organized as uint16_t arrays.
* @details This asynchronous function starts a simultaneous transmit/receive
* operation.
* @post At the end of the operation the configured callback is invoked.
* @note The buffers are organized as uint8_t arrays for data sizes below or
* equal to 8 bits else it is organized as uint16_t arrays.
*
* @param[in] spip pointer to the @p SPIDriver object
* @param[in] n number of words to be exchanged
@ -405,11 +420,13 @@ void spi_lld_exchange(SPIDriver *spip, size_t n,
spip->spd_dmaccr | DMA_CCR1_TCIE | DMA_CCR1_MINC);
dmaChannelSetup(spip->spd_dmatx, n, txbuf,
spip->spd_dmaccr | DMA_CCR1_DIR | DMA_CCR1_MINC);
spi_start_wait(spip);
dma_start(spip);
}
/**
* @brief Sends data ever the SPI bus.
* @brief Sends data over the SPI bus.
* @details This asynchronous function starts a transmit operation.
* @post At the end of the operation the configured callback is invoked.
* @note The buffers are organized as uint8_t arrays for data sizes below or
* equal to 8 bits else it is organized as uint16_t arrays.
*
@ -426,11 +443,13 @@ void spi_lld_send(SPIDriver *spip, size_t n, const void *txbuf) {
spip->spd_dmaccr | DMA_CCR1_TCIE);
dmaChannelSetup(spip->spd_dmatx, n, txbuf,
spip->spd_dmaccr | DMA_CCR1_DIR | DMA_CCR1_MINC);
spi_start_wait(spip);
dma_start(spip);
}
/**
* @brief Receives data from the SPI bus.
* @details This asynchronous function starts a receive operation.
* @post At the end of the operation the configured callback is invoked.
* @note The buffers are organized as uint8_t arrays for data sizes below or
* equal to 8 bits else it is organized as uint16_t arrays.
*
@ -447,7 +466,7 @@ void spi_lld_receive(SPIDriver *spip, size_t n, void *rxbuf) {
spip->spd_dmaccr | DMA_CCR1_TCIE | DMA_CCR1_MINC);
dmaChannelSetup(spip->spd_dmatx, n, &dummytx,
spip->spd_dmaccr | DMA_CCR1_DIR);
spi_start_wait(spip);
dma_start(spip);
}
#endif /* CH_HAL_USE_SPI */

View File

@ -161,45 +161,90 @@
/*===========================================================================*/
/**
* @brief Driver configuration structure.
* @brief Type of a structure representing an SPI driver.
*/
typedef struct SPIDriver SPIDriver;
/**
* @brief SPI notification callback type.
*
* @param[in] spip pointer to the @p SPIDriver object triggering the
* callback
*/
typedef void (*spicallback_t)(SPIDriver *spip);
/**
* @brief Driver configuration structure.
*/
typedef struct {
/** @brief The chip select line port.*/
/**
* @brief Operation complete callback.
*/
spicallback_t spc_endcb;
/* End of the mandatory fields.*/
/**
* @brief The chip select line port.
*/
ioportid_t spc_ssport;
/** @brief The chip select line pad number.*/
/**
* @brief The chip select line pad number.
*/
uint16_t spc_sspad;
/** @brief SPI initialization data.*/
/**
* @brief SPI initialization data.
*/
uint16_t spc_cr1;
} SPIConfig;
/**
* @brief Structure representing a SPI driver.
* @brief Structure representing a SPI driver.
*/
typedef struct {
/** @brief Driver state.*/
struct SPIDriver{
/**
* @brief Driver state.
*/
spistate_t spd_state;
#if SPI_USE_WAIT || defined(__DOXYGEN__)
/**
* @brief Waiting thread.
*/
Thread *spd_thread;
#endif /* SPI_USE_WAIT */
#if SPI_USE_MUTUAL_EXCLUSION || defined(__DOXYGEN__)
#if CH_USE_MUTEXES || defined(__DOXYGEN__)
/** @brief Mutex protecting the bus.*/
/**
* @brief Mutex protecting the bus.
*/
Mutex spd_mutex;
#elif CH_USE_SEMAPHORES
Semaphore spd_semaphore;
#endif
#endif /* SPI_USE_MUTUAL_EXCLUSION */
/** @brief Current configuration data.*/
/**
* @brief Current configuration data.
*/
const SPIConfig *spd_config;
#if defined(SPI_DRIVER_EXT_FIELDS)
SPI_DRIVER_EXT_FIELDS
#endif
/* End of the mandatory fields.*/
/** @brief Thread waiting for I/O completion.*/
Thread *spd_thread;
/** @brief Pointer to the SPIx registers block.*/
/**
* @brief Pointer to the SPIx registers block.
*/
SPI_TypeDef *spd_spi;
/** @brief Pointer to the receive DMA channel registers block.*/
/**
* @brief Pointer to the receive DMA channel registers block.
*/
stm32_dma_channel_t *spd_dmarx;
/** @brief Pointer to the transmit DMA channel registers block.*/
/**
* @brief Pointer to the transmit DMA channel registers block.
*/
stm32_dma_channel_t *spd_dmatx;
/** @brief DMA priority bit mask.*/
/**
* @brief DMA priority bit mask.\
*/
uint32_t spd_dmaccr;
} SPIDriver;
};
/*===========================================================================*/
/* Driver macros. */

View File

@ -198,24 +198,42 @@ typedef void (*uartecb_t)(UARTDriver *uartp, uartflags_t e);
* @note It could be empty on some architectures.
*/
typedef struct {
/** @brief End of transmission buffer callback.*/
/**
* @brief End of transmission buffer callback.
*/
uartcb_t uc_txend1;
/** @brief Physical end of transmission callback.*/
/**
* @brief Physical end of transmission callback.
*/
uartcb_t uc_txend2;
/** @brief Receive buffer filled callback.*/
/**
* @brief Receive buffer filled callback.
*/
uartcb_t uc_rxend;
/** @brief Character received while out if the @p UART_RECEIVE state.*/
uartccb_t uc_rxchar;
/** @brief Receive error callback.*/
uartecb_t uc_rxerr;
/**
* @brief Character received while out if the @p UART_RECEIVE state.
*/
uartcb_t uc_rxchar;
/**
* @brief Receive error callback.
*/
uartcb_t uc_rxerr;
/* End of the mandatory fields.*/
/** @brief Bit rate.*/
/**
* @brief Bit rate.
*/
uint32_t uc_speed;
/** @brief Initialization value for the CR1 register.*/
/**
* @brief Initialization value for the CR1 register.
*/
uint16_t uc_cr1;
/** @brief Initialization value for the CR2 register.*/
/**
* @brief Initialization value for the CR2 register.
*/
uint16_t uc_cr2;
/** @brief Initialization value for the CR3 register.*/
/**
* @brief Initialization value for the CR3 register.
*/
uint16_t uc_cr3;
} UARTConfig;
@ -223,31 +241,49 @@ typedef struct {
* @brief Structure representing an UART driver.
*/
struct UARTDriver {
/** @brief Driver state.*/
/**
* @brief Driver state.
*/
uartstate_t ud_state;
/** @brief Current configuration data.*/
const UARTConfig *ud_config;
/** @brief Transmitter state.*/
/**
* @brief Transmitter state.
*/
uarttxstate_t ud_txstate;
/** @brief Receiver state.*/
/**
* @brief Receiver state.
*/
uartrxstate_t ud_rxstate;
/** @brief UART driver status flags.*/
uartflags_t ud_flags;
/**
* @brief Current configuration data.
*/
const UARTConfig *ud_config;
#if defined(UART_DRIVER_EXT_FIELDS)
UART_DRIVER_EXT_FIELDS
#endif
/* End of the mandatory fields.*/
/** @brief Pointer to the USART registers block.*/
/**
* @brief Pointer to the USART registers block.
*/
USART_TypeDef *ud_usart;
/** @brief Pointer to the DMA registers block.*/
/**
* @brief Pointer to the DMA registers block.
*/
stm32_dma_t *ud_dmap;
/** @brief DMA priority bit mask.*/
/**
* @brief DMA priority bit mask.
*/
uint32_t ud_dmaccr;
/** @brief Receive DMA channel.*/
/**
* @brief Receive DMA channel.
*/
uint8_t ud_dmarx;
/** @brief Transmit DMA channel.*/
/**
* @brief Transmit DMA channel.
*/
uint8_t ud_dmatx;
/** @brief Default receive buffer while into @p UART_RX_IDLE state.*/
/**
* @brief Default receive buffer while into @p UART_RX_IDLE state.
*/
volatile uint16_t ud_rxbuf;
};

View File

@ -65,8 +65,11 @@ void i2cInit(void) {
*/
void i2cObjectInit(I2CDriver *i2cp) {
i2cp->i2c_state = I2C_STOP;
i2cp->i2c_config = NULL;
i2cp->i2c_state = I2C_STOP;
i2cp->i2c_config = NULL;
#if defined(I2C_DRIVER_EXT_INIT_HOOK)
I2C_DRIVER_EXT_INIT_HOOK(i2cp);
#endif
}
/**

View File

@ -67,6 +67,9 @@ void pwmObjectInit(PWMDriver *pwmp) {
pwmp->pd_state = PWM_STOP;
pwmp->pd_config = NULL;
#if defined(PWM_DRIVER_EXT_INIT_HOOK)
PWM_DRIVER_EXT_INIT_HOOK(pwmp);
#endif
}
/**

View File

@ -77,6 +77,10 @@ void spiObjectInit(SPIDriver *spip) {
#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
}
/**
@ -165,9 +169,10 @@ void spiUnselect(SPIDriver *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, while this is not
* usually required by the SPI protocol it is required by
* initialization procedure of MMC/SD cards in SPI mode.
* 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
@ -179,13 +184,12 @@ void spiUnselect(SPIDriver *spip) {
*/
void spiSynchronize(SPIDriver *spip, size_t n) {
chDbgCheck((spip != NULL) && (n > 0), "spiIgnore");
chDbgCheck((spip != NULL) && (n > 0), "spiSynchronize");
chSysLock();
chDbgAssert(spip->spd_state == SPI_READY,
"spiSynchronize(), #1",
"not ready");
spiSynchronizeI(spip, n);
chSysUnlock();
}
@ -240,7 +244,7 @@ void spiExchange(SPIDriver *spip, size_t n, const void *txbuf, void *rxbuf) {
chSysLock();
chDbgAssert(spip->spd_state == SPI_SELECTED,
"spiExchange(), #1",
"not active");
"not selected");
spiExchangeI(spip, n, txbuf, rxbuf);
chSysUnlock();
}
@ -268,7 +272,7 @@ void spiSend(SPIDriver *spip, size_t n, const void *txbuf) {
chSysLock();
chDbgAssert(spip->spd_state == SPI_SELECTED,
"spiSend(), #1",
"not active");
"not selected");
spiSendI(spip, n, txbuf);
chSysUnlock();
}
@ -296,45 +300,28 @@ void spiReceive(SPIDriver *spip, size_t n, void *rxbuf) {
chSysLock();
chDbgAssert(spip->spd_state == SPI_SELECTED,
"spiReceive(), #1",
"not active");
"not selected");
spiReceiveI(spip, n, rxbuf);
chSysUnlock();
}
#if SPI_USE_WAIT || defined(__DOXYGEN__)
/**
* @brief Awakens the thread waiting for operation completion, if any.
*
* @param[in] spip pointer to the @p SPIDriver object
*
* @notapi
*/
void _spi_wakeup(SPIDriver *spip) {
if (spip->spd_thread != NULL) {
Thread *tp = spip->spd_thread;
spip->spd_thread = NULL;
tp->p_u.rdymsg = RDY_RESET;
chSchReadyI(tp);
}
}
/**
* @brief Wait for operation completion.
* @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
* @return The wait status.
* @retval RDY_OK There was not operation running when the function
* has been invoked.
* @retval RDY_RESET The operation completed.
*
* @api
*/
msg_t spiWait(SPIDriver *spip) {
msg_t msg;
void spiWait(SPIDriver *spip) {
chDbgCheck(spip != NULL, "spiWait");
@ -343,20 +330,167 @@ msg_t spiWait(SPIDriver *spip) {
(spip->spd_state == SPI_SELECTED) ||
(spip->spd_state == SPI_ACTIVE) ||
(spip->spd_state == SPI_SYNC),
"spiUnselect(), #1",
"spiWait(), #1",
"invalid state");
chDbgAssert(spip->spd_thread == NULL, "spiWait(), #3", "already waiting");
if ((spip->spd_state == SPI_ACTIVE) || (spip->spd_state == SPI_SYNC)) {
spip->spd_thread = chThdSelf();
chSchGoSleepS(spip->spd_thread, THD_STATE_SUSPENDED);
msg = chThdSelf()->p_u.rdymsg;
}
else
msg = RDY_OK;
if ((spip->spd_state == SPI_ACTIVE) || (spip->spd_state == SPI_SYNC))
spiWaitS(spip);
chSysUnlock();
return msg;
}
/**
* @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.
*
* @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) {
chDbgCheck((spip != NULL) && (n > 0), "spiIgnoreWait");
chSysLock();
chDbgAssert(spip->spd_state == SPI_SELECTED,
"spiIgnoreWait(), #1",
"not selected");
spiIgnoreI(spip, n);
spiWaitS(spip);
chSysUnlock();
}
/**
* @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.
* @note The buffers are organized as uint8_t arrays for data sizes below
* or equal to 8 bits else it is organized as uint16_t arrays.
*
* @param[in] spip pointer to the @p SPIDriver object
* @param[in] n number of words to be exchanged
* @param[in] txbuf the pointer to the transmit buffer
* @param[out] rxbuf the pointer to the receive buffer
*
* @api
*/
void spiExchangeWait(SPIDriver *spip, size_t n,
const void *txbuf, void *rxbuf) {
chDbgCheck((spip != NULL) && (n > 0) && (rxbuf != NULL) && (txbuf != NULL),
"spiExchangeWait");
chSysLock();
chDbgAssert(spip->spd_state == SPI_SELECTED,
"spiExchangeWait(), #1",
"not selected");
spiExchangeI(spip, n, txbuf, rxbuf);
spiWaitS(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.
* @note The buffers are organized as uint8_t arrays for data sizes below
* or equal to 8 bits else it is organized as uint16_t arrays.
*
* @param[in] spip pointer to the @p SPIDriver object
* @param[in] n number of words to send
* @param[in] txbuf the pointer to the transmit buffer
*
* @api
*/
void spiSendWait(SPIDriver *spip, size_t n, const void *txbuf) {
chDbgCheck((spip != NULL) && (n > 0) && (txbuf != NULL),
"spiSendWait");
chSysLock();
chDbgAssert(spip->spd_state == SPI_SELECTED,
"spiSendWait(), #1",
"not selected");
spiSendI(spip, n, txbuf);
spiWaitS(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.
* @note The buffers are organized as uint8_t arrays for data sizes below
* or equal to 8 bits else it is organized as uint16_t arrays.
*
* @param[in] spip pointer to the @p SPIDriver object
* @param[in] n number of words to receive
* @param[out] rxbuf the pointer to the receive buffer
*
* @api
*/
void spiReceiveWait(SPIDriver *spip, size_t n, void *rxbuf) {
chDbgCheck((spip != NULL) && (n > 0) && (rxbuf != NULL),
"spiReceiveWait");
chSysLock();
chDbgAssert(spip->spd_state == SPI_SELECTED,
"spiReceiveWait(), #1",
"not selected");
spiReceiveI(spip, n, rxbuf);
spiWaitS(spip);
chSysUnlock();
}
#endif /* SPI_USE_WAIT */
#if SPI_USE_MUTUAL_EXCLUSION || defined(__DOXYGEN__)

View File

@ -69,6 +69,10 @@ void uartObjectInit(UARTDriver *uartp) {
uartp->ud_txstate = UART_TX_IDLE;
uartp->ud_rxstate = UART_RX_IDLE;
uartp->ud_config = NULL;
/* Optional, user-defined initializer.*/
#if defined(UART_DRIVER_EXT_INIT_HOOK)
UART_DRIVER_EXT_INIT_HOOK(uartp);
#endif
}
/**

View File

@ -35,11 +35,6 @@
#ifndef _HALCONF_H_
#define _HALCONF_H_
/*
* Enable the following line in order to include a mcu-related
* settings file. This file can be used to include platform specific
* header files or to override the low level drivers settings.
*/
#include "mcuconf.h"
/*===========================================================================*/
@ -154,7 +149,16 @@
#endif
/**
* @brief Enables the mutual exclusion APIs on the SPI bus.
* @brief Enables the "wait" APIs.
* @note Disabling this option saves both code and data space.
*/
#if !defined(SPI_USE_WAIT) || defined(__DOXYGEN__)
#define SPI_USE_WAIT TRUE
#endif
/**
* @brief Enables the @p spiAcquireBus() and @p spiReleaseBus() APIs.
* @note Disabling this option saves both code and data space.
*/
#if !defined(SPI_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__)
#define SPI_USE_MUTUAL_EXCLUSION TRUE

View File

@ -110,9 +110,9 @@ void spi_lld_unselect(SPIDriver *spip) {
/**
* @brief Ignores data on the SPI bus.
* @details This function transmits a series of idle words on the SPI bus and
* ignores the received data. This function can be invoked even
* when a slave select signal has not been yet asserted.
* @details This asynchronous function starts the transmission of a series of
* idle words on the SPI bus and ignores the received data.
* @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 ignored
@ -125,7 +125,9 @@ void spi_lld_ignore(SPIDriver *spip, size_t n) {
/**
* @brief Exchanges data on the SPI bus.
* @details This function performs a simultaneous transmit/receive operation.
* @details This asynchronous function starts a simultaneous transmit/receive
* operation.
* @post At the end of the operation the configured callback is invoked.
* @note The buffers are organized as uint8_t arrays for data sizes below or
* equal to 8 bits else it is organized as uint16_t arrays.
*
@ -142,7 +144,9 @@ void spi_lld_exchange(SPIDriver *spip, size_t n,
}
/**
* @brief Sends data ever the SPI bus.
* @brief Sends data over the SPI bus.
* @details This asynchronous function starts a transmit operation.
* @post At the end of the operation the configured callback is invoked.
* @note The buffers are organized as uint8_t arrays for data sizes below or
* equal to 8 bits else it is organized as uint16_t arrays.
*
@ -158,6 +162,8 @@ void spi_lld_send(SPIDriver *spip, size_t n, const void *txbuf) {
/**
* @brief Receives data from the SPI bus.
* @details This asynchronous function starts a receive operation.
* @post At the end of the operation the configured callback is invoked.
* @note The buffers are organized as uint8_t arrays for data sizes below or
* equal to 8 bits else it is organized as uint16_t arrays.
*

View File

@ -46,6 +46,10 @@
/* Driver data structures and types. */
/*===========================================================================*/
/**
* @brief Type of a structure representing an SPI driver.
*/
typedef struct SPIDriver SPIDriver;
/**
* @brief SPI notification callback type.
@ -65,6 +69,7 @@ typedef struct {
* @brief Operation complete callback.
*/
spicallback_t spc_endcb;
/* End of the mandatory fields.*/
} SPIConfig;
/**
@ -72,7 +77,7 @@ typedef struct {
* @note Implementations may extend this structure to contain more,
* architecture dependent, fields.
*/
typedef struct {
struct SPIDriver {
/**
* @brief Driver state.
*/
@ -97,8 +102,11 @@ typedef struct {
* @brief Current configuration data.
*/
const SPIConfig *spd_config;
#if defined(SPI_DRIVER_EXT_FIELDS)
SPI_DRIVER_EXT_FIELDS
#endif
/* End of the mandatory fields.*/
} SPIDriver;
};
/*===========================================================================*/
/* Driver macros. */

View File

@ -87,15 +87,25 @@ typedef void (*uartecb_t)(UARTDriver *uartp, uartflags_t e);
* architecture dependent, fields.
*/
typedef struct {
/** @brief End of transmission buffer callback.*/
/**
* @brief End of transmission buffer callback.
*/
uartcb_t uc_txend1;
/** @brief Physical end of transmission callback.*/
/**
* @brief Physical end of transmission callback.
*/
uartcb_t uc_txend2;
/** @brief Receive buffer filled callback.*/
/**
* @brief Receive buffer filled callback.
*/
uartcb_t uc_rxend;
/** @brief Character received while out if the @p UART_RECEIVE state.*/
/**
* @brief Character received while out if the @p UART_RECEIVE state.
*/
uartcb_t uc_rxchar;
/** @brief Receive error callback.*/
/**
* @brief Receive error callback.
*/
uartcb_t uc_rxerr;
/* End of the mandatory fields.*/
} UARTConfig;

View File

@ -93,18 +93,24 @@
2.0.3).
- FIX: Fixed a documentation error regarding the ADC driver function
adcStartConversion() (bug 3039890)(backported to 2.0.3).
- NEW: Added an ADC_DRIVER_EXT_FIELDS macro to the ADCDriver structure
in order to be able to insert extra fields.
- NEW: Added an PWM_DRIVER_EXT_FIELDS macro to the PWMDriver structure
in order to be able to insert extra fields.
- NEW: Added an UART_DRIVER_EXT_FIELDS macro to the UARTDriver structure
in order to be able to insert extra fields.
- NEW: More assertions added to the kernel.
- NEW: New kernel hooks: SYSTEM_TICK_EVENT_HOOK(), SYSTEM_HALT_HOOK().
- NEW: Added board files for the Olimex STM32-H103.
- NEW: New kernel APIs chSysGetIdleThread() and chThdGetTicks(), the new
APIs are simple macros so there is no footprint overhead.
- NEW: New I2C device driver model (not complete and no implementations yet).
- 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.
- 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().
- NEW: Added to the UART driver the capability to return the number of
not yet transferred frames when stopping an operation.
- NEW: Added more compile-time checks to the various STM32 device drivers.
@ -112,14 +118,11 @@
- NEW: Added a simple STM32 CAN demo under ./testhal/STM32/CAN.
- NEW: Added a simple STM32 PWM demo under ./testhal/STM32/PWM.
- NEW: Added a simple STM32 SPI demo under ./testhal/STM32/SPI.
- NEW: Added pwmEnableChannelI() and pwmDisableChannelI() APIs to the PWM
driver in order to allow channel reprogramming from within callbacks or
other 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 other
interrupt handlers. Made the adcWaitConversion() API optional, this allows
to save some space in Flash/RAM if it is not required.
- NEW: More assertions added to the kernel for improved bug fixing.
- NEW: New kernel hooks: SYSTEM_TICK_EVENT_HOOK(), SYSTEM_HALT_HOOK().
- NEW: Added board files for the Olimex STM32-H103.
- NEW: New kernel APIs chSysGetIdleThread() and chThdGetTicks(), the new
APIs are simple macros so there is no footprint overhead.
- NEW: Added a generic BaseFileStream interface for future File System
implementations or integrations (untested and not sure if it will stay or
change).
@ -130,7 +133,7 @@
semaphores.
- OPT: The fix to the bug 3075544 considerably improved the threads creation
benchmarks score.
- OPT: Speed optimizations to the STM32 SPI driver, improved latency.
- OPT: Speed optimizations to the STM32 SPI driver, greatly improved latency.
- OPT: Speed optimizations to the STM32 ADC driver.
- CHANGE: The API chThdInit() has been renamed to chThdCreateI() in order to
make clear it is usable from interrupt handlers.

View File

@ -14,14 +14,22 @@ Within 2.1.x (hopefully)
verifiable.
* Rework STM32 drivers to use friendly IRQ names and centralized DMA macros.
* I-class functions for the ADC/PWM drivers.
* All the device driver structures must have a fields extension macro and
initializer hook.
* All the device driver callbacks must have the driver pointer as first
parameter.
X All the device driver structures must have a fields extension macro.
* Change the SPI driver to be able to work asynchronously with callbacks,
keep the synchronous APIs available as option.
* Update the STM32 SPI driver.
- Update the AT91SAM7 SPI driver.
- Update the LPC214x SPI driver.
- Write an SPI driver for LPC1xxx.
- Make the ADC, I2C and UART drivers have the same "wait" semantic like
the new SPI driver model.
X Resist doing more changes and optimizations in the kernel, fixes only.
X File System infrastructure.
X General HAL improvements.
X I2C device driver class support.
- Evaluate making SPI and CAN drivers callback-based.
X I2C device driver class support and at least one implementation.
- MAC driver for STM32F105/STM32F107 (hardware missing).
- Device drivers for STM8 (SPI, ADC, PWM, bring it on par with STM32).
- Support for more compilers (ARMCMx only initially).